From 8f4ed824733a26b3f5aaba685ef15c1c7d333f28 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 23 Apr 2019 10:39:38 +0700 Subject: [PATCH] Merge remote-tracking branch 'origin/master' GitOrigin-RevId: 4aa2198b0e40383875028553977a5721ba77766d --- build/conf/nsis/idea.nsi | 5 +- .../thumbnail/impl/ThumbnailViewUI.java | 5 +- .../dataFlow/CustomMethodHandlers.java | 18 +- .../completion/AllClassesGetter.java | 3 +- .../JavaClassNameCompletionContributor.java | 1 + .../completion/JavaCompletionUtil.java | 13 +- .../JavaDocCompletionContributor.java | 3 +- .../completion/JavaStaticMemberProcessor.java | 2 +- .../LimitedAccessibleClassPreprocessor.java | 11 +- .../completion/StaticMemberProcessor.java | 2 +- ...SimplifyStreamApiCallChainsInspection.java | 10 +- .../FoldExpressionIntoStreamInspection.java | 7 +- .../streamMigration/JoiningMigration.java | 19 +- .../call/JavaCallReferenceProcessor.java | 25 +- .../impl/search/AllClassesSearchExecutor.java | 15 +- .../ide/hierarchy/call/DirectRecursion/A.java | 9 + .../DirectRecursion_verification.xml | 5 + .../hierarchy/call/IndirectRecursion/A.java | 13 + .../IndirectRecursion_verification.xml | 8 + .../completion/EditorTabOutTest.java | 9 + .../ide/hierarchy/JavaCallHierarchyTest.java | 8 + .../openapi/vfs/CompactVirtualFileSet.java | 28 +- .../com/intellij/ui/SimpleTextAttributes.java | 13 +- .../ide/plugins/cl/PluginClassLoader.java | 1 + .../com/intellij/diff/DiffDialogHints.java | 21 +- .../src/com/intellij/diff/DiffManagerEx.java | 4 + .../com/intellij/diff/DiffRequestFactory.java | 7 + .../intellij/diff/merge/MergeCallback.java | 60 ++ .../diff/merge/MergeRequestProducer.java | 19 + .../com/intellij/diff/DiffManagerImpl.java | 8 +- .../intellij/diff/DiffRequestFactoryImpl.java | 48 +- .../intellij/diff/impl/DiffWindowBase.java | 4 + .../intellij/diff/merge/ErrorMergeTool.java | 7 +- .../diff/merge/MergeRequestProcessor.java | 201 +++-- .../com/intellij/diff/merge/MergeUtil.java | 29 +- .../com/intellij/diff/merge/MergeWindow.java | 193 ++--- .../diff/merge/MessageMergeViewer.java | 59 ++ .../intellij/diff/merge/TextMergeViewer.java | 68 +- .../diff/requests/BinaryMergeRequestImpl.java | 14 +- .../diff/requests/TextMergeRequestImpl.java | 14 +- .../diff/tools/external/ExternalDiffTool.java | 35 +- .../tools/util/side/ThreesideDiffViewer.java | 8 +- platform/dvcs-impl/src/META-INF/dvcs.xml | 1 + .../intellij/dvcs/repo/ClonePathProvider.java | 63 ++ .../com/intellij/dvcs/ui/CloneDvcsDialog.java | 49 +- .../ExternalSystemEventDispatcher.kt | 6 +- .../project/manage/SourceFolderManagerImpl.kt | 5 +- .../com/intellij/util/indexing/IdFilter.java | 15 +- .../psi/impl/search/LowLevelSearchUtil.java | 20 +- .../psi/search/FileNameIndexService.java | 2 +- .../intellij/psi/search/FilenameIndex.java | 2 +- .../properties/BraceStyleAccessor.java | 59 +- .../properties/FieldAccessorFactory.java | 4 +- .../properties/ForceBracesAccessor.java | 52 +- .../properties/MagicIntegerConstAccessor.java | 43 ++ .../properties/WrappingAccessor.java | 57 +- .../output/BuildOutputInstantReader.java | 4 +- .../build/output/BuildOutputParser.java | 1 - .../editorActions/TabOutScopesTracker.java | 18 +- .../src/com/intellij/formatting/Block.java | 2 + .../codeStyle/CommonCodeStyleSettings.java | 1 + .../output/BuildOutputInstantReaderImpl.kt | 18 +- .../build/output/JavacOutputParser.java | 12 +- .../build/output/KotlincOutputParser.kt | 18 +- .../documentation/DocumentationComponent.java | 23 +- .../documentation/DocumentationManager.java | 4 +- .../editorActions/BraceOrQuoteOutAction.java | 5 +- .../TabOutScopesTrackerImpl.java | 33 +- .../template/impl/TemplateImpl.java | 2 +- .../extapi/psi/MetadataPsiElementBase.java | 74 -- .../intellij/extapi/psi/PsiElementBase.java | 293 -------- .../formatting/InitialInfoBuilder.java | 41 +- .../ConfigureCodeStyleOnSelectedFragment.java | 2 + .../ide/actions/GotoFileItemProvider.java | 2 +- .../CreateWithTemplatesDialogPanel.java | 87 ++- .../AbstractGotoSEContributor.java | 13 +- .../ContributorsBasedGotoByModel.java | 11 +- .../psi/search/FileNameIndexServiceImpl.java | 2 +- .../proximity/PsiProximityComparator.java | 8 +- .../BuildOutputInstantReaderImplTest.kt | 2 +- .../execution/process/AnsiCommands.java | 87 +++ .../execution/process/AnsiEscapeDecoder.java | 224 ++---- .../execution/process/AnsiStreamingLexer.java | 162 ++++ .../execution/process/AnsiTerminalColor.java | 31 + .../process/AnsiTerminalEmulator.java | 702 ++++++++++++++++++ .../process/ColoredOutputTypeRegistry.java | 128 +++- .../intellij/openapi/ui/DialogWrapper.java | 43 +- .../intellij/ui/SimpleColoredComponent.java | 17 +- .../intellij/diagnostic/IdeErrorsDialog.java | 2 +- .../com/intellij/ide/actions/Switcher.java | 38 +- .../actions/ViewInplaceCommentsAction.java | 13 + .../PluginManagerConfigurableNewLayout.java | 101 +-- .../ide/plugins/newui/PluginLogo.java | 30 +- .../ide/plugins/newui/PluginLogoApi.java | 174 +++++ .../ide/plugins/newui/SearchQueryParser.java | 33 +- .../ide/ui/AppearanceConfigurable.java | 6 +- .../intellij/ide/ui/laf/LafManagerImpl.java | 16 +- .../ide/ui/laf/darcula/darcula.properties | 10 +- .../ide/ui/laf/intellijlaf.properties | 10 +- .../ide/ui/laf/intellijlaf_mac.properties | 4 + .../ide/ui/laf/intellijlaf_native.properties | 10 +- .../diff/impl/mergeTool/MergeVersion.java | 36 - .../impl/EditorGutterComponentImpl.java | 11 +- .../options/newEditor/SettingsTreeView.java | 2 +- .../com/intellij/openapi/ui/FrameWrapper.java | 37 +- .../openapi/ui/WindowWrapperBuilder.java | 22 +- .../openapi/vfs/newvfs/RefreshQueueImpl.java | 10 +- .../vfs/newvfs/persistent/RefreshWorker.java | 5 + .../header/CustomHeader.kt | 17 +- .../intellij/ui/tree/ui/ClassicPainter.java | 5 +- .../intellij/ui/tree/ui/CompactPainter.java | 5 +- .../src/com/intellij/ui/tree/ui/Control.java | 5 +- .../intellij/ui/tree/ui/DefaultControl.java | 3 +- .../intellij/ui/tree/ui/DefaultTreeUI.java | 2 +- .../src/META-INF/PlatformExtensions.xml | 2 +- .../src/idea/PlatformActions.xml | 2 + .../process/AnsiEscapeDecoderTest.java | 183 +++-- .../editor/impl/IterationStateTest.java | 31 +- .../editor/impl/softwrap/SoftWrapTest.java | 4 + ...apApplianceOnDocumentModificationTest.java | 58 +- .../ui/tree/ui/TreeControlPainterTest.java | 3 +- .../concurrency/BackgroundTaskQueueTest.java | 2 +- .../testFramework/LightProjectDescriptor.java | 17 +- .../util/resources/misc/registry.properties | 10 +- .../util/containers/ContainerUtil.java | 22 + .../containers/FilteredTraverserBase.java | 9 +- .../util/src/com/intellij/util/io/IOUtil.java | 13 +- .../util/src/com/intellij/util/ui/JBUI.java | 25 + .../src/com/intellij/vcsUtil/VcsUtil.java | 16 + .../com/intellij/openapi/vcs/ZipAndQueue.java | 19 +- .../DefaultPatchBaseVersionProvider.java | 28 +- .../patch/PatchDiffRequestFactory.java | 6 +- .../patch/tool/ApplyPatchMergeRequest.java | 14 +- .../ui/ChangesBrowserNodeRenderer.java | 2 +- .../changes/ui/ChangesViewContentManager.java | 87 ++- .../vcs/merge/MergeConflictsTreeTable.kt | 48 ++ .../vcs/merge/MultipleFileMergeDialog.kt | 50 +- .../StringEqualsCharSequenceInspection.java | 19 +- ...ngBufferReplaceableByStringInspection.java | 3 +- .../application/CvsEntriesManager.java | 10 +- ...CvsStorageSupportingDeletionComponent.java | 2 +- .../git4idea/resources/META-INF/plugin.xml | 7 + .../GitConflictsToolWindowManager.java | 69 ++ .../git4idea/conflicts/GitConflictsView.kt | 270 +++++++ .../git4idea/conflicts/GitMergeHandler.java | 197 +++++ .../conflicts/MergeConflictResolveUtil.kt | 139 ++++ .../src/git4idea/merge/GitMergeProvider.java | 103 +-- .../src/git4idea/merge/GitMergeUtil.java | 68 +- .../src/git4idea/repo/GitConflict.java | 62 ++ .../src/git4idea/repo/GitConflictsHolder.java | 69 ++ .../src/git4idea/repo/GitRepository.java | 3 + .../src/git4idea/repo/GitRepositoryImpl.java | 16 +- .../git4idea/status/GitChangeProvider.java | 4 + .../git4idea/status/GitChangesCollector.java | 76 +- .../git4idea/test/MockGitRepository.java | 6 + .../META-INF/gradle-groovy-integration.xml | 3 +- .../META-INF/gradle-java-integration.xml | 2 - .../GradleJavaOutputParserProvider.java | 29 - .../resolve/GradleDomainObjectProperty.kt | 10 + .../resolve/GradleExtensionsContributor.kt | 77 +- .../resolve/GradleIdeaSettingsContributor.kt | 8 +- .../service/resolve/GradleMiscContributor.kt | 6 +- .../GradleNamedDomainCollectionContributor.kt | 58 ++ .../GradleNonCodeMembersContributor.kt | 59 +- .../GradleProjectExtensionContributor.kt | 66 ++ .../GradleUnresolvedReferenceFilter.java | 31 +- ...medDomainObjectCollectionTypeEnhancer.java | 106 --- .../dsl/GradleDistributionsTest.groovy | 62 +- .../testSources/dsl/GradleTasksTest.groovy | 22 +- .../output/GradleBuildScriptErrorParser.kt | 2 +- .../output/GradleOutputDispatcherFactory.kt | 27 +- .../output/GradleOutputParserProvider.java | 15 +- .../build/output/GradleSyncOutputParser.java | 5 +- .../importing/GradleFoldersImportingTest.java | 29 + .../ExternalTestsModelBuilderImpl.groovy | 8 +- .../builder/JsonBuilderContributor.java | 12 +- .../builder/JsonDelegateContributor.java | 8 +- .../StreamingJsonBuilderContributor.java | 6 +- ...MarkupBuilderNonCodeMemberContributor.java | 14 +- .../lang/psi/impl/GroovyPsiManager.java | 4 +- .../lang/psi/impl/InferenceContext.java | 4 +- .../groovy/lang/psi/impl/PartialContext.kt | 4 +- .../lang/psi/impl/TopInferenceContext.kt | 4 +- .../blocks/GrClosableBlockImpl.java | 5 +- .../statements/expressions/ClassUtil.java | 6 +- .../GrAssignmentExpressionImpl.java | 2 +- .../typedef/members/GrMethodBaseImpl.java | 2 +- .../synthetic/ClosureSyntheticParameter.java | 19 +- .../lang/resolve/api/SimpleGroovyProperty.kt | 11 + .../delegatesTo/DefaultDelegatesToProvider.kt | 6 +- .../resolve/delegatesTo/grDelegatesToUtil.kt | 10 +- .../LogbackDelegateMemberContributor.kt | 6 +- .../completion/GrMainCompletionProvider.java | 2 +- .../groovy/GroovyGotoDeclarationTest.groovy | 4 +- .../GroovyLightProjectDescriptor.groovy | 38 - .../jetbrains/plugins/groovy/SetupRule.groovy | 20 +- .../groovy/builder/JsonBuilderTest.groovy | 21 +- .../builder/StreamingJsonBuilderTest.groovy | 20 +- .../GroovyMoveLeftRightHandlerTest.groovy | 6 +- ...oovyInlayParameterHintsProviderTest.groovy | 4 +- ...oovyIdenticalBranchesInspectionTest.groovy | 20 +- ...nnecessaryDefModifierInspectionTest.groovy | 20 +- ...cessaryPublicModifierInspectionTest.groovy | 23 +- ...rUnnecessarySemicolonInspectionTest.groovy | 6 +- ...nusedDefaultParameterInspectionTest.groovy | 21 +- ...derTransformationCompletionTestBase.groovy | 20 +- .../MiscBuilderTransformationTest.groovy | 20 +- .../ext/newify/NewifyResolveTest.groovy | 6 +- .../ext/newify/NewifySupportTest.groovy | 6 +- .../ext/spock/SpockLineMarkersTest.groovy | 20 +- .../CreateConstantFromJavaUsageTest.groovy | 7 +- .../fixes/GrLoosePrecisionFixTest.groovy | 6 +- .../fixes/GrMultipleAssignmentTest.groovy | 6 +- .../groovy/fixes/GrSpreadArgumentTest.groovy | 20 +- .../geb/AbstractGebLightTestCase.groovy | 64 -- .../plugins/groovy/geb/GebTestsTest.groovy | 33 +- .../groovy/ide/GroovyRunLineMarkerTest.groovy | 6 +- .../inspections/GrChangeToMethodTest.groovy | 35 +- .../inspections/GrChangeToOperatorTest.groovy | 6 +- .../GrMethodMayBeStaticTest.groovy | 20 +- .../highlighting/GrClosureParamsTest.groovy | 4 +- .../GrHighlightingAttributesTest.groovy | 6 +- .../GrLatestHighlightingTest.groovy | 6 +- .../GroovyHighlightUsagesTest.groovy | 4 +- .../groovy/lang/psi/ModifiersTest.groovy | 8 +- .../FromAbstractTypeMethodsTest.groovy | 20 +- .../resolve/ConstantExpressionTest.groovy | 6 +- .../lang/resolve/CustomMapPropertyTest.groovy | 4 +- .../resolve/DelegatesToSupportTest.groovy | 20 +- .../resolve/GrImportContributorTest.groovy | 4 +- .../lang/resolve/GrNumericLUBTypeTest.groovy | 20 +- .../resolve/GroovyTraitCoercionTest.groovy | 20 +- .../lang/resolve/MapPropertyTest.groovy | 6 +- .../NavigateDelegatedClsMethodsTest.groovy | 39 +- .../lang/resolve/NumberMathTypingTest.groovy | 4 +- .../lang/resolve/ResolveAttributeTest.groovy | 6 +- .../lang/resolve/ResolveClassInNewTest.groovy | 6 +- .../resolve/ResolveFieldVsAccessorTest.groovy | 6 +- .../resolve/ResolveIndexPropertyTest.groovy | 6 +- .../ResolveOperatorAssignmentTest.groovy | 20 +- ...ResolvePropertyViaAliasedImportTest.groovy | 6 +- .../ResolveWithDelegatesToOnLambdaTest.groovy | 4 +- .../resolve/ResolveWithDelegatesToTest.groovy | 6 +- .../lang/resolve/SelfTypeSupportTest.groovy | 20 +- .../dgm/ResolveDGMMethodLatestTest.groovy | 20 +- .../dgm/ResolveExtensionMethodTest.groovy | 4 +- .../modifiers/GrVisibilityTestBase.groovy | 20 +- .../rename/InplaceRenameTest.groovy | 20 +- ...BaseScriptTransformationSupportTest.groovy | 20 +- ...rAutoCloneTransformationSupportTest.groovy | 4 +- .../GrNoTransformationsTest.groovy | 8 +- .../GrTransformationsTest.groovy | 6 +- .../SynchronizedTransformationTest.groovy | 20 +- .../ImmutableTransformationSupportTest.groovy | 6 +- .../IndexedPropertyTest.groovy | 20 +- .../listenerList/ListenerListTest.groovy | 20 +- .../SingletonConstructorInspectionTest.groovy | 20 +- .../SingletonNewInstanceInspectionTest.groovy | 20 +- .../SingletonTransformationSupportTest.groovy | 20 +- .../plugins/groovy/util/ExpressionTest.java | 54 ++ .../groovy/util/ReferenceExpressionTest.java | 16 - .../mockGeb/geb-core-0.7.1-sources.jar | Bin 84962 -> 0 bytes .../testdata/mockGeb/geb-core-0.7.1.jar | Bin 221593 -> 0 bytes .../testdata/mockGeb/geb-junit4-0.7.0.jar | Bin 7700 -> 0 bytes .../testdata/mockGeb/geb-spock-0.7.1.jar | Bin 9305 -> 0 bytes .../testdata/mockGeb/geb-testng-0.7.2.jar | Bin 8010 -> 0 bytes .../output/MavenImportOutputParser.java | 6 +- .../output/MavenBuildToolLogTestUtils.java | 2 +- .../editor/ResourceBundleEditor.java | 15 +- .../pydev/_pydev_bundle/pydev_monkey.py | 67 +- .../jetbrains/python/formatter/PyBlock.java | 2 +- .../python/sdk/PythonSdkUpdater.java | 26 +- .../tox/PyToxConfigurationProducer.java | 4 +- .../tox/PyToxConfigurationSettings.form | 2 +- .../testing/tox/PyToxConfigurationType.java | 2 +- .../debug/test_executable_script_debug.py | 7 + .../test_executable_script_debug_helper.py | 5 + .../env/python/PythonDebuggerTest.java | 24 + .../src/com/jetbrains/python/tools/Utils.kt | 2 +- .../src/org/jetbrains/index/stubs/SdkUtils.kt | 3 +- 280 files changed, 4726 insertions(+), 3079 deletions(-) create mode 100644 java/java-tests/testData/ide/hierarchy/call/DirectRecursion/A.java create mode 100644 java/java-tests/testData/ide/hierarchy/call/DirectRecursion/DirectRecursion_verification.xml create mode 100644 java/java-tests/testData/ide/hierarchy/call/IndirectRecursion/A.java create mode 100644 java/java-tests/testData/ide/hierarchy/call/IndirectRecursion/IndirectRecursion_verification.xml create mode 100644 platform/diff-api/src/com/intellij/diff/merge/MergeCallback.java create mode 100644 platform/diff-api/src/com/intellij/diff/merge/MergeRequestProducer.java create mode 100644 platform/diff-impl/src/com/intellij/diff/merge/MessageMergeViewer.java create mode 100644 platform/dvcs-impl/src/com/intellij/dvcs/repo/ClonePathProvider.java create mode 100644 platform/lang-api/src/com/intellij/application/options/codeStyle/properties/MagicIntegerConstAccessor.java rename {java/compiler/impl => platform/lang-impl}/src/com/intellij/build/output/JavacOutputParser.java (90%) rename {java/compiler/impl => platform/lang-impl}/src/com/intellij/build/output/KotlincOutputParser.kt (85%) delete mode 100644 platform/lang-impl/src/com/intellij/extapi/psi/MetadataPsiElementBase.java delete mode 100644 platform/lang-impl/src/com/intellij/extapi/psi/PsiElementBase.java create mode 100644 platform/platform-api/src/com/intellij/execution/process/AnsiCommands.java create mode 100644 platform/platform-api/src/com/intellij/execution/process/AnsiStreamingLexer.java create mode 100644 platform/platform-api/src/com/intellij/execution/process/AnsiTerminalColor.java create mode 100644 platform/platform-api/src/com/intellij/execution/process/AnsiTerminalEmulator.java create mode 100644 platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginLogoApi.java create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/merge/MergeConflictsTreeTable.kt create mode 100644 plugins/git4idea/src/git4idea/conflicts/GitConflictsToolWindowManager.java create mode 100644 plugins/git4idea/src/git4idea/conflicts/GitConflictsView.kt create mode 100644 plugins/git4idea/src/git4idea/conflicts/GitMergeHandler.java create mode 100644 plugins/git4idea/src/git4idea/conflicts/MergeConflictResolveUtil.kt create mode 100644 plugins/git4idea/src/git4idea/repo/GitConflict.java create mode 100644 plugins/git4idea/src/git4idea/repo/GitConflictsHolder.java delete mode 100644 plugins/gradle/java/src/execution/build/output/GradleJavaOutputParserProvider.java create mode 100644 plugins/gradle/java/src/service/resolve/GradleDomainObjectProperty.kt create mode 100644 plugins/gradle/java/src/service/resolve/GradleNamedDomainCollectionContributor.kt create mode 100644 plugins/gradle/java/src/service/resolve/GradleProjectExtensionContributor.kt delete mode 100644 plugins/gradle/java/src/service/resolve/NamedDomainObjectCollectionTypeEnhancer.java create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/SimpleGroovyProperty.kt delete mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyLightProjectDescriptor.groovy delete mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/geb/AbstractGebLightTestCase.groovy create mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/util/ExpressionTest.java delete mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/util/ReferenceExpressionTest.java delete mode 100644 plugins/groovy/testdata/mockGeb/geb-core-0.7.1-sources.jar delete mode 100644 plugins/groovy/testdata/mockGeb/geb-core-0.7.1.jar delete mode 100644 plugins/groovy/testdata/mockGeb/geb-junit4-0.7.0.jar delete mode 100644 plugins/groovy/testdata/mockGeb/geb-spock-0.7.1.jar delete mode 100644 plugins/groovy/testdata/mockGeb/geb-testng-0.7.2.jar create mode 100644 python/testData/debug/test_executable_script_debug.py create mode 100644 python/testData/debug/test_executable_script_debug_helper.py diff --git a/build/conf/nsis/idea.nsi b/build/conf/nsis/idea.nsi index ba2d6c266fd6..663c28d15e59 100644 --- a/build/conf/nsis/idea.nsi +++ b/build/conf/nsis/idea.nsi @@ -1881,8 +1881,11 @@ skip_delete_settings: !insertmacro INSTALLOPTIONS_READ $R3 "DeleteSettings.ini" "Field 7" "State" StrCmp $R3 1 "" skip_delete_tools SetShellVarContext current - IfFileExists "$LOCALAPPDATA\${MANUFACTURER}\BuildTools\*.*" 0 continue_uninstall + IfFileExists "$LOCALAPPDATA\${MANUFACTURER}\BuildTools\*.*" 0 delete_downloaded_jdk8 RmDir /r "$LOCALAPPDATA\${MANUFACTURER}\BuildTools" +delete_downloaded_jdk8: + IfFileExists "$LOCALAPPDATA\${MANUFACTURER}\jdk8\*.*" 0 continue_uninstall + RmDir /r "$LOCALAPPDATA\${MANUFACTURER}\jdk8" continue_uninstall: StrCmp $baseRegKey "HKLM" 0 skip_delete_tools diff --git a/images/src/org/intellij/images/thumbnail/impl/ThumbnailViewUI.java b/images/src/org/intellij/images/thumbnail/impl/ThumbnailViewUI.java index dde58f0d1e66..b0293d4c918a 100644 --- a/images/src/org/intellij/images/thumbnail/impl/ThumbnailViewUI.java +++ b/images/src/org/intellij/images/thumbnail/impl/ThumbnailViewUI.java @@ -68,7 +68,6 @@ import java.util.List; import java.util.*; final class ThumbnailViewUI extends JPanel implements DataProvider, Disposable { - private final VirtualFileListener vfsListener = new VFSListener(); private final OptionsChangeListener optionsListener = new OptionsChangeListener(); private static final Navigatable[] EMPTY_NAVIGATABLE_ARRAY = new Navigatable[]{}; @@ -107,7 +106,7 @@ final class ThumbnailViewUI extends JPanel implements DataProvider, Disposable { cellRenderer = new ThumbnailListCellRenderer(); ImageComponent imageComponent = cellRenderer.getImageComponent(); - VirtualFileManager.getInstance().addVirtualFileListener(vfsListener); + VirtualFileManager.getInstance().addVirtualFileListener(new VFSListener(), this); Options options = OptionsManager.getInstance().getOptions(); EditorOptions editorOptions = options.getEditorOptions(); @@ -624,8 +623,6 @@ final class ThumbnailViewUI extends JPanel implements DataProvider, Disposable { Options options = OptionsManager.getInstance().getOptions(); options.removePropertyChangeListener(optionsListener); - VirtualFileManager.getInstance().removeVirtualFileListener(vfsListener); - list = null; cellRenderer = null; tagsPanel = null; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java index 6065d07a76a3..75ccbe8f3168 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java @@ -1,18 +1,4 @@ -/* - * 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-2019 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. package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; @@ -163,7 +149,7 @@ class CustomMethodHandlers { if (TypeUtils.isJavaLangObject(type)) { return Object.class; } - if (TypeUtils.typeEquals("java.lang.CharSequence", type)) { + if (TypeUtils.typeEquals(JAVA_LANG_CHARSEQUENCE, type)) { return CharSequence.class; } if (PsiType.INT.equals(type)) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java index dfbd37f7650d..904bcf8f80b5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java @@ -119,7 +119,7 @@ public class AllClassesGetter { final Project project = context.getProject(); final GlobalSearchScope scope = filterByScope ? context.getContainingFile().getResolveScope() : GlobalSearchScope.allScope(project); - processJavaClasses(prefixMatcher, project, scope, new LimitedAccessibleClassPreprocessor(parameters, filterByScope, consumer)); + processJavaClasses(prefixMatcher, project, scope, new LimitedAccessibleClassPreprocessor(parameters, filterByScope, c->{consumer.consume(c); return true;})); } public static void processJavaClasses(@NotNull final PrefixMatcher prefixMatcher, @@ -131,6 +131,7 @@ public class AllClassesGetter { if (prefixMatcher.prefixMatches(s)) { names.add(s); } + return true; }); LinkedHashSet sorted = CompletionUtil.sortMatching(prefixMatcher, names); AllClassesSearchExecutor.processClassesByNames(project, scope, sorted, processor); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java index 1166a3b4c504..b26f2f559eeb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java @@ -106,6 +106,7 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { JavaPsiClassReferenceElement item = AllClassesGetter.createLookupItem(anno, JAVA_CLASS_INSERT_HANDLER); item.addLookupStrings(getClassNameWithContainers(anno)); consumer.consume(item); + return true; }); for (String name : CompletionUtil.sortMatching(matcher, annoMap.keySet())) { if (!ContainerUtil.process(annoMap.get(name), processor)) break; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 7440dc967e4a..72b4420df83b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -7,6 +7,7 @@ import com.intellij.codeInsight.completion.scope.CompletionElement; import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; +import com.intellij.codeInsight.editorActions.TabOutScopesTracker; import com.intellij.codeInsight.guess.GuessManager; import com.intellij.codeInsight.lookup.*; import com.intellij.codeInspection.java15api.Java15APIUsageInspection; @@ -98,7 +99,7 @@ public class JavaCompletionUtil { JavaMemberNameCompletionContributor.completeVariableNameForRefactoring(project, set, camelHumpMatcher, varType, varKind, true, false); } - public static void putAllMethods(LookupElement item, List methods) { + public static void putAllMethods(LookupElement item, List methods) { item.putUserData(ALL_METHODS_ATTRIBUTE, ContainerUtil.map(methods, method -> SmartPointerManager.getInstance(method.getProject()).createSmartPsiElementPointer(method))); } @@ -827,7 +828,15 @@ public class JavaCompletionUtil { } } - toInsert.processTail(context.getEditor(), context.getTailOffset()); + Editor editor = context.getEditor(); + int tailOffset = context.getTailOffset(); + int afterTailOffset = toInsert.processTail(editor, tailOffset); + int caretOffset = editor.getCaretModel().getOffset(); + if (afterTailOffset > tailOffset && + tailOffset > caretOffset && + TabOutScopesTracker.getInstance().removeScopeEndingAt(editor, caretOffset) > 0) { + TabOutScopesTracker.getInstance().registerEmptyScope(editor, caretOffset, afterTailOffset - caretOffset); + } return true; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java index bc1f47f82d08..10da8ed151c2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java @@ -223,7 +223,8 @@ public class JavaDocCompletionContributor extends CompletionContributor { for (LookupElement element : completeJavadocReference(ref.getElement(), ref)) { result.addElement(LookupElementDecorator.withInsertHandler(element, wrapIntoLinkTag((context, item) -> element.handleInsert(context)))); } - } else if (matcher.getPrefix().length() > 0) { + } + else if (matcher.getPrefix().length() > 0) { InsertHandler handler = wrapIntoLinkTag(JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER); AllClassesGetter.processJavaClasses(parameters, matcher, parameters.getInvocationCount() == 1, psiClass -> result.addElement(AllClassesGetter.createLookupItem(psiClass, handler))); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java index 37120f20cac2..ccc4f235f057 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java @@ -69,7 +69,7 @@ public class JavaStaticMemberProcessor extends StaticMemberProcessor { } @Override - protected LookupElement createLookupElement(@NotNull List overloads, + protected LookupElement createLookupElement(@NotNull List overloads, @NotNull PsiClass containingClass, boolean shouldImport) { shouldImport |= myOriginalPosition != null && PsiTreeUtil.isAncestor(containingClass, myOriginalPosition, false); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/LimitedAccessibleClassPreprocessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/LimitedAccessibleClassPreprocessor.java index 98f18602e73a..b95c63e4384b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/LimitedAccessibleClassPreprocessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/LimitedAccessibleClassPreprocessor.java @@ -20,7 +20,6 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl; -import com.intellij.util.Consumer; import com.intellij.util.Processor; import gnu.trove.THashSet; @@ -34,18 +33,18 @@ class LimitedAccessibleClassPreprocessor implements Processor { private final PsiElement myContext; private final CompletionParameters myParameters; private final boolean myFilterByScope; - private final Consumer myConsumer; + private final Processor myProcessor; private final int myLimit = Registry.intValue("ide.completion.variant.limit"); private int myCount; private final Set myQNames = new THashSet<>(); private final boolean myPkgContext; private final String myPackagePrefix; - LimitedAccessibleClassPreprocessor(CompletionParameters parameters, boolean filterByScope, Consumer consumer) { + LimitedAccessibleClassPreprocessor(CompletionParameters parameters, boolean filterByScope, Processor processor) { myContext = parameters.getPosition(); myParameters = parameters; myFilterByScope = filterByScope; - myConsumer = consumer; + myProcessor = processor; myPkgContext = JavaCompletionUtil.inSomePackage(myContext); myPackagePrefix = getPackagePrefix(myContext, myParameters.getOffset()); } @@ -70,7 +69,7 @@ class LimitedAccessibleClassPreprocessor implements Processor { return true; } String name = psiClass.getName(); - if (name != null && name.length() > 0 && Character.isLowerCase(name.charAt(0)) && + if (name != null && !name.isEmpty() && Character.isLowerCase(name.charAt(0)) && !Registry.is("ide.completion.show.lower.case.classes")) { return true; } @@ -83,7 +82,7 @@ class LimitedAccessibleClassPreprocessor implements Processor { LOG.debug("Processing class " + qName); } if (qName != null && qName.startsWith(myPackagePrefix) && myQNames.add(qName)) { - myConsumer.consume(psiClass); + if (!myProcessor.process(psiClass)) return false; if (++myCount > myLimit) { LOG.debug("Limit reached"); return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java index 69da72b66e4f..c6427736dfa3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java @@ -147,5 +147,5 @@ public abstract class StaticMemberProcessor { @Nullable protected abstract LookupElement createLookupElement(@NotNull PsiMember member, @NotNull PsiClass containingClass, boolean shouldImport); - protected abstract LookupElement createLookupElement(@NotNull List overloads, @NotNull PsiClass containingClass, boolean shouldImport); + protected abstract LookupElement createLookupElement(@NotNull List overloads, @NotNull PsiClass containingClass, boolean shouldImport); } diff --git a/java/java-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java b/java/java-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java index b92ef68a9be0..19e27c6dcdbb 100644 --- a/java/java-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java @@ -1,4 +1,4 @@ -// 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-2019 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. package com.intellij.codeInspection; import com.intellij.codeInsight.ExpressionUtil; @@ -1773,7 +1773,7 @@ public class SimplifyStreamApiCallChainsInspection extends AbstractBaseJavaLocal static final CallMatcher COLLECTOR_JOINING = staticCall(JAVA_UTIL_STREAM_COLLECTORS, "joining") .parameterCount(0); static final CallMatcher COLLECTOR_JOINING_DELIMITER = staticCall(JAVA_UTIL_STREAM_COLLECTORS, "joining") - .parameterTypes("java.lang.CharSequence"); + .parameterTypes(JAVA_LANG_CHARSEQUENCE); @Override public String getName() { @@ -1826,7 +1826,7 @@ public class SimplifyStreamApiCallChainsInspection extends AbstractBaseJavaLocal if (ARRAYS_STREAM.matches(qualifier) || (COLLECTION_STREAM.matches(qualifier) && ExpressionUtils.getEffectiveQualifier(qualifier.getMethodExpression()) != null)) { PsiType elementType = StreamApiUtil.getStreamElementType(qualifier.getType()); - if (InheritanceUtil.isInheritor(elementType, "java.lang.CharSequence")) { + if (InheritanceUtil.isInheritor(elementType, JAVA_LANG_CHARSEQUENCE)) { return new JoiningStringsFix(); } } @@ -1911,11 +1911,11 @@ public class SimplifyStreamApiCallChainsInspection extends AbstractBaseJavaLocal if (PsiUtil.skipParenthesizedExprDown(argumentExpressions[1]) != call) return null; PsiExpression delimiter = argumentExpressions[0]; if (delimiter == null) return null; - if(!InheritanceUtil.isInheritor(delimiter.getType(), "java.lang.CharSequence")) return null; + if(!InheritanceUtil.isInheritor(delimiter.getType(), JAVA_LANG_CHARSEQUENCE)) return null; PsiMethodCallExpression stream = getQualifierMethodCall(call); if (stream == null) return null; PsiType elementType = StreamApiUtil.getStreamElementType(stream.getType()); - if (!InheritanceUtil.isInheritor(elementType, "java.lang.CharSequence")) return null; + if (!InheritanceUtil.isInheritor(elementType, JAVA_LANG_CHARSEQUENCE)) return null; return new Context(maybeJoinCall, delimiter, argument); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/FoldExpressionIntoStreamInspection.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/FoldExpressionIntoStreamInspection.java index b608a3c0a07a..0a2f408f6c50 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/FoldExpressionIntoStreamInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/FoldExpressionIntoStreamInspection.java @@ -1,4 +1,4 @@ -// 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-2019 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. package com.intellij.codeInspection.streamMigration; import com.intellij.codeInspection.*; @@ -26,6 +26,7 @@ import java.util.List; import java.util.Objects; import static com.intellij.codeInsight.intention.impl.StreamRefactoringUtil.getMapOperationName; +import static com.intellij.psi.CommonClassNames.JAVA_LANG_CHARSEQUENCE; import static com.intellij.util.ObjectUtils.tryCast; public class FoldExpressionIntoStreamInspection extends AbstractBaseJavaLocalInspectionTool { @@ -137,7 +138,7 @@ public class FoldExpressionIntoStreamInspection extends AbstractBaseJavaLocalIns PsiExpression[] operands = polyadicExpression.getOperands(); String mapToString; PsiType operandType = operands[0].getType(); - if (!InheritanceUtil.isInheritor(operandType, "java.lang.CharSequence")) { + if (!InheritanceUtil.isInheritor(operandType, JAVA_LANG_CHARSEQUENCE)) { if (!StreamApiUtil.isSupportedStreamElement(operandType)) return null; mapToString = "."+getMapOperationName(operandType, type)+"(String::valueOf)"; } else { @@ -150,7 +151,7 @@ public class FoldExpressionIntoStreamInspection extends AbstractBaseJavaLocalIns .pairMap(EquivalenceChecker.getCanonicalPsiEquivalence()::expressionsAreEquivalent) .allMatch(Boolean.TRUE::equals)) { delimiter = operands[1]; - if (!InheritanceUtil.isInheritor(delimiter.getType(), "java.lang.CharSequence") && + if (!InheritanceUtil.isInheritor(delimiter.getType(), JAVA_LANG_CHARSEQUENCE) && !(delimiter instanceof PsiLiteralExpression && PsiType.CHAR.equals(delimiter.getType()))) { return null; } diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/JoiningMigration.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/JoiningMigration.java index 22e755dea893..71f788d4f6fa 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/JoiningMigration.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/JoiningMigration.java @@ -1,18 +1,4 @@ -/* - * 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-2019 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. package com.intellij.codeInspection.streamMigration; @@ -41,6 +27,7 @@ import java.util.function.Predicate; import static com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil.isEffectivelyFinal; import static com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.isCallOf; +import static com.intellij.psi.CommonClassNames.JAVA_LANG_CHARSEQUENCE; import static com.intellij.util.ObjectUtils.tryCast; import static com.siyeh.ig.psiutils.ControlFlowUtils.getInitializerUsageStatus; import static com.siyeh.ig.psiutils.ExpressionUtils.resolveLocalVariable; @@ -330,7 +317,7 @@ public class JoiningMigration extends BaseStreamApiMigration { } } } - if (!InheritanceUtil.isInheritor(type, "java.lang.CharSequence")) { + if (!InheritanceUtil.isInheritor(type, JAVA_LANG_CHARSEQUENCE)) { if (!neighborIsString || (type instanceof PsiArrayType && ((PsiArrayType)type).getComponentType().equals(PsiType.CHAR))) { PsiLiteralExpression literalExpression = tryCast(expression, PsiLiteralExpression.class); if (literalExpression != null) { diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/call/JavaCallReferenceProcessor.java b/java/java-impl/src/com/intellij/ide/hierarchy/call/JavaCallReferenceProcessor.java index 808aeb4720b7..c3d7b24ac553 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/call/JavaCallReferenceProcessor.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/call/JavaCallReferenceProcessor.java @@ -84,11 +84,13 @@ public class JavaCallReferenceProcessor implements CallReferenceProcessor { final PsiElement element = reference.getElement(); final PsiMember key = CallHierarchyNodeDescriptor.getEnclosingElement(element); + CallHierarchyNodeDescriptor parentDescriptor = (CallHierarchyNodeDescriptor) data.getNodeDescriptor(); + if (isRecursiveNode(method, parentDescriptor)) return false; synchronized (methodToDescriptorMap) { CallHierarchyNodeDescriptor d = (CallHierarchyNodeDescriptor)methodToDescriptorMap.get(key); if (d == null) { - d = new CallHierarchyNodeDescriptor(myProject, (CallHierarchyNodeDescriptor)data.getNodeDescriptor(), element, false, true); + d = new CallHierarchyNodeDescriptor(myProject, parentDescriptor, element, false, true); methodToDescriptorMap.put(key, d); } else if (!d.hasReference(reference)) { @@ -98,4 +100,25 @@ public class JavaCallReferenceProcessor implements CallReferenceProcessor { } return false; } + + private static boolean isRecursiveNode(@NotNull PsiMethod method, @NotNull CallHierarchyNodeDescriptor parentDescriptor) { + // detect recursion + // the current call-site calls *method* + // Thus, we already have a node that represents *method* + // Check whether we have any other node along the parent-chain that represents that same method + + NodeDescriptor ancestorDescriptor = parentDescriptor; + // Start check on grandparent + while ((ancestorDescriptor = ancestorDescriptor.getParentDescriptor()) != null) { + if (ancestorDescriptor instanceof CallHierarchyNodeDescriptor) { + PsiMember ancestorCallSite = ((CallHierarchyNodeDescriptor)ancestorDescriptor).getEnclosingElement(); + if (ancestorCallSite == method) { + // We have at least two occurrences in the parent chain of method already + // Don't search any deeper + return true; + } + } + } + return false; + } } diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/AllClassesSearchExecutor.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/AllClassesSearchExecutor.java index ebd764b92cb4..b852305487a4 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/AllClassesSearchExecutor.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/AllClassesSearchExecutor.java @@ -17,7 +17,6 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.AllClassesSearch; -import com.intellij.util.Consumer; import com.intellij.util.Processor; import com.intellij.util.QueryExecutor; import com.intellij.util.indexing.IdFilter; @@ -50,6 +49,7 @@ public class AllClassesSearchExecutor implements QueryExecutor sorted = new ArrayList<>(names); @@ -75,18 +75,15 @@ public class AllClassesSearchExecutor implements QueryExecutor consumer) { - DumbService.getInstance(project).runReadActionInSmartMode((Computable)() -> { + public static boolean processClassNames(final Project project, final GlobalSearchScope scope, final Processor processor) { + boolean success = DumbService.getInstance(project).runReadActionInSmartMode((Computable)() -> PsiShortNamesCache.getInstance(project).processAllClassNames(s -> { ProgressManager.checkCanceled(); - consumer.consume(s); - return true; - }, scope, IdFilter.getProjectIdFilter(project, true)); - return null; - }); + return processor.process(s); + }, scope, IdFilter.getProjectIdFilter(project, true))); ProgressManager.checkCanceled(); - return project; + return success; } private static boolean processScopeRootForAllClasses(@NotNull final PsiElement scopeRoot, @NotNull final Processor processor) { diff --git a/java/java-tests/testData/ide/hierarchy/call/DirectRecursion/A.java b/java/java-tests/testData/ide/hierarchy/call/DirectRecursion/A.java new file mode 100644 index 000000000000..b2f5460a32fc --- /dev/null +++ b/java/java-tests/testData/ide/hierarchy/call/DirectRecursion/A.java @@ -0,0 +1,9 @@ +// Copyright 2000-2019 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. +class A { + public static void main(String[] args) { + recursive(); + } + public static void recursive() { + recursive(); + } +} diff --git a/java/java-tests/testData/ide/hierarchy/call/DirectRecursion/DirectRecursion_verification.xml b/java/java-tests/testData/ide/hierarchy/call/DirectRecursion/DirectRecursion_verification.xml new file mode 100644 index 000000000000..d8101f0674d8 --- /dev/null +++ b/java/java-tests/testData/ide/hierarchy/call/DirectRecursion/DirectRecursion_verification.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/java/java-tests/testData/ide/hierarchy/call/IndirectRecursion/A.java b/java/java-tests/testData/ide/hierarchy/call/IndirectRecursion/A.java new file mode 100644 index 000000000000..255c46fe530a --- /dev/null +++ b/java/java-tests/testData/ide/hierarchy/call/IndirectRecursion/A.java @@ -0,0 +1,13 @@ +// Copyright 2000-2019 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. +class A { + public static void main(String[] args) { + recursive1(); + } + public static void recursive1() { + recursive2(); + } + + public static void recursive2() { + recursive1(); + } +} diff --git a/java/java-tests/testData/ide/hierarchy/call/IndirectRecursion/IndirectRecursion_verification.xml b/java/java-tests/testData/ide/hierarchy/call/IndirectRecursion/IndirectRecursion_verification.xml new file mode 100644 index 000000000000..cc117a25fd0e --- /dev/null +++ b/java/java-tests/testData/ide/hierarchy/call/IndirectRecursion/IndirectRecursion_verification.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/EditorTabOutTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/EditorTabOutTest.java index 99656ecd19c1..4d29cb4673e5 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/EditorTabOutTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/EditorTabOutTest.java @@ -90,6 +90,15 @@ public class EditorTabOutTest extends AbstractParameterInfoTestCase { "}"); } + public void testSemicolon() { + configureJava("class C { void m() { System.exi } }"); + complete("exit"); + checkResult("class C { void m() { System.exit(); } }"); + type('1'); + tabOut(); + checkResult("class C { void m() { System.exit(1); } }"); + } + private void tabOut() { myFixture.performEditorAction(IdeActions.ACTION_BRACE_OR_QUOTE_OUT); } diff --git a/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java b/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java index 47bc9e6edf88..9ef56c77ff69 100644 --- a/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java +++ b/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java @@ -58,6 +58,14 @@ public class JavaCallHierarchyTest extends HierarchyViewTestBase { doJavaCallTypeHierarchyTest("B", "xyzzy", "B.java", "D.java", "A.java"); } + public void testDirectRecursion() throws Exception { + doJavaCallTypeHierarchyTest("A", "recursive", "A.java"); + } + + public void testIndirectRecursion() throws Exception { + doJavaCallTypeHierarchyTest("A", "recursive2", "A.java"); + } + public void testIdeaDev41005_Inheritance() throws Exception { doJavaCallTypeHierarchyTest("D", "xyzzy", "B.java", "D.java", "A.java", "C.java"); } diff --git a/platform/core-api/src/com/intellij/openapi/vfs/CompactVirtualFileSet.java b/platform/core-api/src/com/intellij/openapi/vfs/CompactVirtualFileSet.java index 262a0f117277..cb70612a8136 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/CompactVirtualFileSet.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/CompactVirtualFileSet.java @@ -5,12 +5,9 @@ import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import gnu.trove.TIntHashSet; -import gnu.trove.TIntIterator; -import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import java.util.*; -import java.util.function.IntFunction; /** * Set of VirtualFiles optimized for compact storage of very large number of files @@ -146,31 +143,8 @@ public class CompactVirtualFileSet extends AbstractSet { Iterator idsIterator = ids == null ? Collections.emptyIterator() : ContainerUtil.mapIterator(ids.stream().iterator(), id -> virtualFileManager.findFileById(id)); Iterator idSetIterator = idSet == null ? Collections.emptyIterator() : - mapIterator(idSet.iterator(), id -> virtualFileManager.findFileById(id)); + ContainerUtil.mapIterator(idSet.iterator(), id -> virtualFileManager.findFileById(id)); Iterator weirdFileIterator = weirdFiles.iterator(); return ContainerUtil.filterIterator(ContainerUtil.concatIterators(idsIterator, idSetIterator, weirdFileIterator), Objects::nonNull); } - - // todo move to ContainerUtil when ported util to java level 8 - @NotNull - @Contract(pure=true) - public static Iterator mapIterator(@NotNull final TIntIterator iterator, @NotNull final IntFunction mapper) { - return new Iterator() { - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public U next() { - return mapper.apply(iterator.next()); - } - - @Override - public void remove() { - iterator.remove(); - } - }; - } - } diff --git a/platform/core-api/src/com/intellij/ui/SimpleTextAttributes.java b/platform/core-api/src/com/intellij/ui/SimpleTextAttributes.java index 10d0971224ae..a530a539bbb6 100644 --- a/platform/core-api/src/com/intellij/ui/SimpleTextAttributes.java +++ b/platform/core-api/src/com/intellij/ui/SimpleTextAttributes.java @@ -21,7 +21,8 @@ public final class SimpleTextAttributes { @MagicConstant(flags = { STYLE_PLAIN, STYLE_BOLD, STYLE_ITALIC, STYLE_STRIKEOUT, STYLE_WAVED, STYLE_UNDERLINE, - STYLE_BOLD_DOTTED_LINE, STYLE_SEARCH_MATCH, STYLE_SMALLER, STYLE_OPAQUE, STYLE_CLICKABLE}) + STYLE_BOLD_DOTTED_LINE, STYLE_SEARCH_MATCH, STYLE_SMALLER, STYLE_OPAQUE, + STYLE_CLICKABLE, STYLE_HOVERED}) public @interface StyleAttributeConstant { } public static final int STYLE_PLAIN = Font.PLAIN; @@ -36,6 +37,7 @@ public final class SimpleTextAttributes { public static final int STYLE_SMALLER = STYLE_SEARCH_MATCH << 1; public static final int STYLE_OPAQUE = STYLE_SMALLER << 1; public static final int STYLE_CLICKABLE = STYLE_OPAQUE << 1; + public static final int STYLE_HOVERED = STYLE_CLICKABLE << 1; public static final SimpleTextAttributes REGULAR_ATTRIBUTES = new SimpleTextAttributes(STYLE_PLAIN, null); public static final SimpleTextAttributes REGULAR_BOLD_ATTRIBUTES = new SimpleTextAttributes(STYLE_BOLD, null); @@ -83,7 +85,7 @@ public final class SimpleTextAttributes { this(null, fgColor, waveColor, style); } - public SimpleTextAttributes(@Nullable final Color bgColor, final Color fgColor, @Nullable final Color waveColor, @StyleAttributeConstant int style) { + public SimpleTextAttributes(@Nullable Color bgColor, Color fgColor, @Nullable Color waveColor, @StyleAttributeConstant int style) { if ((~(STYLE_PLAIN | STYLE_BOLD | STYLE_ITALIC | @@ -94,7 +96,8 @@ public final class SimpleTextAttributes { STYLE_SEARCH_MATCH | STYLE_SMALLER | STYLE_OPAQUE | - STYLE_CLICKABLE) & style) != 0) { + STYLE_CLICKABLE | + STYLE_HOVERED) & style) != 0) { throw new IllegalArgumentException("Wrong style: " + style); } @@ -172,6 +175,10 @@ public final class SimpleTextAttributes { return BitUtil.isSet(myStyle, STYLE_CLICKABLE); } + public boolean isHovered() { + return BitUtil.isSet(myStyle, STYLE_HOVERED); + } + @NotNull public static SimpleTextAttributes fromTextAttributes(TextAttributes attributes) { if (attributes == null) return REGULAR_ATTRIBUTES; diff --git a/platform/core-impl/src/com/intellij/ide/plugins/cl/PluginClassLoader.java b/platform/core-impl/src/com/intellij/ide/plugins/cl/PluginClassLoader.java index b148eb75d822..2be73d1adb45 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/cl/PluginClassLoader.java +++ b/platform/core-impl/src/com/intellij/ide/plugins/cl/PluginClassLoader.java @@ -152,6 +152,7 @@ public class PluginClassLoader extends UrlClassLoader { private static final Set KOTLIN_STDLIB_CLASSES_USED_IN_SIGNATURES = ContainerUtil.set( "kotlin.sequences.Sequence", + "kotlin.Lazy", "kotlin.Unit", "kotlin.Pair", "kotlin.Triple", diff --git a/platform/diff-api/src/com/intellij/diff/DiffDialogHints.java b/platform/diff-api/src/com/intellij/diff/DiffDialogHints.java index c921ff64f97c..8e3946902d81 100644 --- a/platform/diff-api/src/com/intellij/diff/DiffDialogHints.java +++ b/platform/diff-api/src/com/intellij/diff/DiffDialogHints.java @@ -16,6 +16,7 @@ package com.intellij.diff; import com.intellij.openapi.ui.WindowWrapper; +import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,19 +33,21 @@ public class DiffDialogHints { // @Nullable private final WindowWrapper.Mode myMode; - @Nullable private Component myParent; + @Nullable private final Component myParent; + @Nullable private final Consumer myWindowConsumer; public DiffDialogHints(@Nullable WindowWrapper.Mode mode) { this(mode, null); } public DiffDialogHints(@Nullable WindowWrapper.Mode mode, @Nullable Component parent) { - myMode = mode; - myParent = parent; + this(mode, parent, null); } - public void setParent(@Nullable Component value) { - myParent = value; + public DiffDialogHints(@Nullable WindowWrapper.Mode mode, @Nullable Component parent, @Nullable Consumer windowConsumer) { + myMode = mode; + myParent = parent; + myWindowConsumer = windowConsumer; } // @@ -60,4 +63,12 @@ public class DiffDialogHints { public Component getParent() { return myParent; } + + /** + * NB: Consumer might not be called at all (ex: for external diff/merge tools, that do not spawn WindowWrapper) + */ + @Nullable + public Consumer getWindowConsumer() { + return myWindowConsumer; + } } diff --git a/platform/diff-api/src/com/intellij/diff/DiffManagerEx.java b/platform/diff-api/src/com/intellij/diff/DiffManagerEx.java index cef525a236aa..5852f78c1bee 100644 --- a/platform/diff-api/src/com/intellij/diff/DiffManagerEx.java +++ b/platform/diff-api/src/com/intellij/diff/DiffManagerEx.java @@ -17,6 +17,7 @@ package com.intellij.diff; import com.intellij.diff.chains.DiffRequestChain; import com.intellij.diff.merge.MergeRequest; +import com.intellij.diff.merge.MergeRequestProducer; import com.intellij.diff.merge.MergeTool; import com.intellij.diff.requests.DiffRequest; import com.intellij.openapi.components.ServiceManager; @@ -50,6 +51,9 @@ public abstract class DiffManagerEx extends DiffManager { @CalledInAwt public abstract void showMergeBuiltin(@Nullable Project project, @NotNull MergeRequest request); + @CalledInAwt + public abstract void showMergeBuiltin(@Nullable Project project, @NotNull MergeRequestProducer request, @NotNull DiffDialogHints hints); + @NotNull public abstract List getDiffTools(); diff --git a/platform/diff-api/src/com/intellij/diff/DiffRequestFactory.java b/platform/diff-api/src/com/intellij/diff/DiffRequestFactory.java index e6040a65403a..ac4fb0f677b8 100644 --- a/platform/diff-api/src/com/intellij/diff/DiffRequestFactory.java +++ b/platform/diff-api/src/com/intellij/diff/DiffRequestFactory.java @@ -91,6 +91,13 @@ public abstract class DiffRequestFactory { @NotNull List contentTitles, @Nullable Consumer applyCallback) throws InvalidDiffRequestException; + @NotNull + public abstract MergeRequest createMergeRequest(@Nullable Project project, + @NotNull VirtualFile output, + @NotNull List byteContents, + @Nullable String title, + @NotNull List contentTitles) throws InvalidDiffRequestException; + @NotNull public abstract TextMergeRequest createTextMergeRequest(@Nullable Project project, @NotNull VirtualFile output, diff --git a/platform/diff-api/src/com/intellij/diff/merge/MergeCallback.java b/platform/diff-api/src/com/intellij/diff/merge/MergeCallback.java new file mode 100644 index 000000000000..5496e78237f6 --- /dev/null +++ b/platform/diff-api/src/com/intellij/diff/merge/MergeCallback.java @@ -0,0 +1,60 @@ +// Copyright 2000-2019 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. +package com.intellij.diff.merge; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Key; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.EventListener; + +import static com.intellij.openapi.diagnostic.Logger.getInstance; + +public class MergeCallback { + private static final Logger LOG = getInstance(MergeCallback.class); + + private static final Key KEY = Key.create("com.intellij.diff.merge.MergeCallback"); + private static final MergeCallback EMPTY = new MergeCallback(); + + public void applyResult(@NotNull MergeResult result) { + } + + public boolean checkIsValid() { + return true; + } + + public void addListener(@NotNull Listener listener, @NotNull Disposable disposable) { + } + + + @NotNull + public static T register(@NotNull T request, @Nullable MergeCallback callback) { + LOG.assertTrue(request.getUserData(KEY) == null); + if (callback != null) request.putUserData(KEY, callback); + return request; + } + + @NotNull + public static T register(@NotNull T request, @Nullable Consumer callback) { + return register(request, new MergeCallback() { + @Override + public void applyResult(@NotNull MergeResult result) { + if (callback != null) callback.consume(result); + } + }); + } + + @NotNull + public static MergeCallback getCallback(@NotNull MergeRequest request) { + MergeCallback callback = request.getUserData(KEY); + return callback != null ? callback : EMPTY; + } + + + public interface Listener extends EventListener { + default void fireConflictInvalid() { + } + } +} diff --git a/platform/diff-api/src/com/intellij/diff/merge/MergeRequestProducer.java b/platform/diff-api/src/com/intellij/diff/merge/MergeRequestProducer.java new file mode 100644 index 000000000000..bc37feb8fdc9 --- /dev/null +++ b/platform/diff-api/src/com/intellij/diff/merge/MergeRequestProducer.java @@ -0,0 +1,19 @@ +// Copyright 2000-2019 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. +package com.intellij.diff.merge; + +import com.intellij.diff.chains.DiffRequestProducerException; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.util.UserDataHolder; +import org.jetbrains.annotations.CalledInBackground; +import org.jetbrains.annotations.NotNull; + +public interface MergeRequestProducer { + @NotNull + String getName(); + + @CalledInBackground + @NotNull + MergeRequest process(@NotNull UserDataHolder context, @NotNull ProgressIndicator indicator) + throws DiffRequestProducerException, ProcessCanceledException; +} diff --git a/platform/diff-impl/src/com/intellij/diff/DiffManagerImpl.java b/platform/diff-impl/src/com/intellij/diff/DiffManagerImpl.java index 44d08d78e6bc..728d376f58be 100644 --- a/platform/diff-impl/src/com/intellij/diff/DiffManagerImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/DiffManagerImpl.java @@ -133,6 +133,12 @@ public class DiffManagerImpl extends DiffManagerEx { @Override @CalledInAwt public void showMergeBuiltin(@Nullable Project project, @NotNull MergeRequest request) { - new MergeWindow(project, request).show(); + new MergeWindow.ForRequest(project, request, DiffDialogHints.MODAL).show(); + } + + @Override + @CalledInAwt + public void showMergeBuiltin(@Nullable Project project, @NotNull MergeRequestProducer requestProducer, @NotNull DiffDialogHints hints) { + new MergeWindow.ForProducer(project, requestProducer, hints).show(); } } diff --git a/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java b/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java index d0f70ee940fe..6820af6d9159 100644 --- a/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/DiffRequestFactoryImpl.java @@ -18,6 +18,7 @@ package com.intellij.diff; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DocumentContent; import com.intellij.diff.contents.FileContent; +import com.intellij.diff.merge.MergeCallback; import com.intellij.diff.merge.MergeRequest; import com.intellij.diff.merge.MergeResult; import com.intellij.diff.merge.TextMergeRequest; @@ -232,7 +233,8 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { contents.add(myContentFactory.create(project, text, fileType)); } - return new TextMergeRequestImpl(project, outputContent, originalContent, contents, title, titles, applyCallback); + TextMergeRequestImpl request = new TextMergeRequestImpl(project, outputContent, originalContent, contents, title, titles); + return MergeCallback.register(request, applyCallback); } @NotNull @@ -243,14 +245,22 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { @Nullable String title, @NotNull List contentTitles, @Nullable Consumer applyCallback) throws InvalidDiffRequestException { - if (byteContents.size() != 3) throw new IllegalArgumentException(); - if (contentTitles.size() != 3) throw new IllegalArgumentException(); + MergeRequest request = createMergeRequest(project, output, byteContents, title, contentTitles); + return MergeCallback.register(request, applyCallback); + } + @NotNull + @Override + public MergeRequest createMergeRequest(@Nullable Project project, + @NotNull VirtualFile output, + @NotNull List byteContents, + @Nullable String title, + @NotNull List contentTitles) throws InvalidDiffRequestException { try { - return createTextMergeRequest(project, output, byteContents, title, contentTitles, applyCallback); + return createTextMergeRequest(project, output, byteContents, title, contentTitles); } catch (InvalidDiffRequestException e) { - return createBinaryMergeRequest(project, output, byteContents, title, contentTitles, applyCallback); + return createBinaryMergeRequest(project, output, byteContents, title, contentTitles); } } @@ -262,6 +272,16 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { @Nullable String title, @NotNull List contentTitles, @Nullable Consumer applyCallback) throws InvalidDiffRequestException { + TextMergeRequest request = createTextMergeRequest(project, output, byteContents, title, contentTitles); + return MergeCallback.register(request, applyCallback); + } + + @NotNull + private TextMergeRequest createTextMergeRequest(@Nullable Project project, + @NotNull VirtualFile output, + @NotNull List byteContents, + @Nullable String title, + @NotNull List contentTitles) throws InvalidDiffRequestException { if (byteContents.size() != 3) throw new IllegalArgumentException(); if (contentTitles.size() != 3) throw new IllegalArgumentException(); @@ -277,7 +297,7 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { contents.add(myContentFactory.createDocumentFromBytes(project, bytes, output)); } - return new TextMergeRequestImpl(project, outputContent, originalContent, contents, title, contentTitles, applyCallback); + return new TextMergeRequestImpl(project, outputContent, originalContent, contents, title, contentTitles); } @NotNull @@ -288,6 +308,16 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { @Nullable String title, @NotNull List contentTitles, @Nullable Consumer applyCallback) throws InvalidDiffRequestException { + MergeRequest request = createBinaryMergeRequest(project, output, byteContents, title, contentTitles); + return MergeCallback.register(request, applyCallback); + } + + @NotNull + private MergeRequest createBinaryMergeRequest(@Nullable Project project, + @NotNull VirtualFile output, + @NotNull List byteContents, + @Nullable String title, + @NotNull List contentTitles) throws InvalidDiffRequestException { if (byteContents.size() != 3) throw new IllegalArgumentException(); if (contentTitles.size() != 3) throw new IllegalArgumentException(); @@ -301,7 +331,7 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { contents.add(myContentFactory.createFromBytes(project, bytes, output)); } - return new BinaryMergeRequestImpl(project, outputContent, originalContent, contents, byteContents, title, contentTitles, applyCallback); + return new BinaryMergeRequestImpl(project, outputContent, originalContent, contents, byteContents, title, contentTitles); } catch (IOException e) { throw new InvalidDiffRequestException("Can't read from file", e); @@ -384,7 +414,9 @@ public class DiffRequestFactoryImpl extends DiffRequestFactory { byteContents.add(file.contentsToByteArray()); // TODO: we can read contents from file when needed } - return new BinaryMergeRequestImpl(project, outputContent, originalContent, contents, byteContents, title, contentTitles, applyCallback); + BinaryMergeRequestImpl request = new BinaryMergeRequestImpl(project, outputContent, originalContent, contents, byteContents, + title, contentTitles); + return MergeCallback.register(request, applyCallback); } catch (IOException e) { throw new InvalidDiffRequestException("Can't read from file", e); diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffWindowBase.java b/platform/diff-impl/src/com/intellij/diff/impl/DiffWindowBase.java index e4d0053e27bd..c223edd68f1a 100644 --- a/platform/diff-impl/src/com/intellij/diff/impl/DiffWindowBase.java +++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffWindowBase.java @@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.WindowWrapper; import com.intellij.openapi.ui.WindowWrapperBuilder; import com.intellij.openapi.util.Disposer; +import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -57,6 +58,9 @@ public abstract class DiffWindowBase { .build(); myWrapper.setImages(DiffUtil.DIFF_FRAME_ICONS); Disposer.register(myWrapper, myProcessor); + + Consumer wrapperHandler = myHints.getWindowConsumer(); + if (wrapperHandler != null) wrapperHandler.consume(myWrapper); } public void show() { diff --git a/platform/diff-impl/src/com/intellij/diff/merge/ErrorMergeTool.java b/platform/diff-impl/src/com/intellij/diff/merge/ErrorMergeTool.java index 70055802dc21..26c6e8dada33 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/ErrorMergeTool.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/ErrorMergeTool.java @@ -48,12 +48,7 @@ public class ErrorMergeTool implements MergeTool { myMergeRequest = request; myPanel = new JPanel(new BorderLayout()); - myPanel.add(createComponent(), BorderLayout.CENTER); - } - - @NotNull - private JComponent createComponent() { - return DiffUtil.createMessagePanel("Can't show diff"); + myPanel.add(DiffUtil.createMessagePanel("Can't show merge"), BorderLayout.CENTER); } @NotNull diff --git a/platform/diff-impl/src/com/intellij/diff/merge/MergeRequestProcessor.java b/platform/diff-impl/src/com/intellij/diff/merge/MergeRequestProcessor.java index 1fc51b5b6790..c66b6340f157 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/MergeRequestProcessor.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/MergeRequestProcessor.java @@ -16,14 +16,25 @@ import com.intellij.notification.NotificationType; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.util.BackgroundTaskUtil; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.BooleanGetter; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; +import com.intellij.ui.EditorNotificationPanel; +import com.intellij.ui.LightColors; +import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.JBEmptyBorder; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.CalledInAwt; @@ -53,17 +64,17 @@ public abstract class MergeRequestProcessor implements Disposable { @NotNull private final Wrapper myContentPanel; @NotNull private final Wrapper myToolbarPanel; @NotNull private final Wrapper myToolbarStatusPanel; + @NotNull private final Wrapper myNotificationPanel; + @NotNull private final Wrapper myButtonsPanel; - @NotNull private final MergeRequest myRequest; + @Nullable private MergeRequest myRequest; @NotNull private MergeTool.MergeViewer myViewer; @Nullable private BooleanGetter myCloseHandler; - @Nullable private BottomActions myBottomActions; private boolean myConflictResolved = false; - public MergeRequestProcessor(@Nullable Project project, @NotNull MergeRequest request) { + public MergeRequestProcessor(@Nullable Project project) { myProject = project; - myRequest = request; myContext = new MyDiffContext(); myContext.putUserData(DiffUserDataKeys.PLACE, DiffPlaces.MERGE); @@ -75,28 +86,23 @@ public abstract class MergeRequestProcessor implements Disposable { myToolbarPanel = new Wrapper(); myToolbarPanel.setFocusable(true); myToolbarStatusPanel = new Wrapper(); + myNotificationPanel = new Wrapper(); + myButtonsPanel = new Wrapper(); myPanel = JBUI.Panels.simplePanel(myMainPanel); - JPanel topPanel = JBUI.Panels.simplePanel(myToolbarPanel).addToRight(myToolbarStatusPanel); + JPanel topPanel = JBUI.Panels.simplePanel(myToolbarPanel) + .addToRight(myToolbarStatusPanel) + .addToBottom(myNotificationPanel); myMainPanel.add(topPanel, BorderLayout.NORTH); myMainPanel.add(myContentPanel, BorderLayout.CENTER); + myMainPanel.add(myButtonsPanel, BorderLayout.SOUTH); myMainPanel.setFocusTraversalPolicyProvider(true); myMainPanel.setFocusTraversalPolicy(new MyFocusTraversalPolicy()); - MergeTool.MergeViewer viewer; - try { - viewer = getFittedTool().createComponent(myContext, myRequest); - } - catch (Throwable e) { - LOG.error(e); - viewer = ErrorMergeTool.INSTANCE.createComponent(myContext, myRequest); - } - - myViewer = viewer; - updateBottomActions(); + myViewer = new MessageMergeViewer(myContext, "Loading..."); } // @@ -104,9 +110,50 @@ public abstract class MergeRequestProcessor implements Disposable { // @CalledInAwt - public void init() { - setTitle(myRequest.getTitle()); + public void init(@NotNull MergeRequest request) { + setTitle(request.getTitle()); + + myRequest = request; + myViewer = createViewerFor(request); initViewer(); + installCallbackListener(myRequest); + } + + @CalledInAwt + public void init(@NotNull MergeRequestProducer request) { + setTitle(request.getName()); + initViewer(); + + ModalityState modality = ModalityState.stateForComponent(myPanel); + BackgroundTaskUtil.executeOnPooledThread(this, () -> { + try { + MergeRequest mergeRequest = request.process(myContext, ProgressManager.getInstance().getProgressIndicator()); + ApplicationManager.getApplication().invokeLater( + () -> { + myRequest = mergeRequest; + swapViewer(createViewerFor(mergeRequest)); + installCallbackListener(myRequest); + }, + modality); + } + catch (Throwable e) { + LOG.warn(e); + ApplicationManager.getApplication().invokeLater( + () -> swapViewer(new MessageMergeViewer(myContext, "Can't show merge: " + e.getMessage())), + modality); + } + }); + } + + @NotNull + private MergeTool.MergeViewer createViewerFor(@NotNull MergeRequest request) { + try { + return getFittedTool(request).createComponent(myContext, request); + } + catch (Throwable e) { + LOG.error(e); + return ErrorMergeTool.INSTANCE.createComponent(myContext, request); + } } @CalledInAwt @@ -118,6 +165,8 @@ public abstract class MergeRequestProcessor implements Disposable { buildToolbar(toolbarComponents.toolbarActions); myToolbarStatusPanel.setContent(toolbarComponents.statusPanel); myCloseHandler = toolbarComponents.closeHandler; + + updateBottomActions(); } @CalledInAwt @@ -129,16 +178,49 @@ public abstract class MergeRequestProcessor implements Disposable { myContentPanel.setContent(null); myToolbarPanel.setContent(null); myToolbarStatusPanel.setContent(null); + myButtonsPanel.setContent(null); myCloseHandler = null; - myBottomActions = null; } private void updateBottomActions() { - myBottomActions = new BottomActions(); - myBottomActions.applyLeft = myViewer.getResolveAction(MergeResult.LEFT); - myBottomActions.applyRight = myViewer.getResolveAction(MergeResult.RIGHT); - myBottomActions.resolveAction = myViewer.getResolveAction(MergeResult.RESOLVED); - myBottomActions.cancelAction = myViewer.getResolveAction(MergeResult.CANCEL); + Action applyLeft = myViewer.getResolveAction(MergeResult.LEFT); + Action applyRight = myViewer.getResolveAction(MergeResult.RIGHT); + Action resolveAction = myViewer.getResolveAction(MergeResult.RESOLVED); + Action cancelAction = myViewer.getResolveAction(MergeResult.CANCEL); + + if (resolveAction != null) { + resolveAction.putValue(DialogWrapper.DEFAULT_ACTION, true); + + new DumbAwareAction() { + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + resolveAction.actionPerformed(null); + } + }.registerCustomShortcutSet(CommonShortcuts.CTRL_ENTER, getRootPane(), this); + } + + List leftActions = ContainerUtil.packNullables(applyLeft, applyRight); + List rightActions = SystemInfo.isMac ? ContainerUtil.packNullables(cancelAction, resolveAction) + : ContainerUtil.packNullables(resolveAction, cancelAction); + + JRootPane rootPane = getRootPane(); + JPanel buttonsPanel = new NonOpaquePanel(new BorderLayout()); + buttonsPanel.setBorder(new JBEmptyBorder(UIUtil.PANEL_REGULAR_INSETS)); + + if (leftActions.size() > 0) { + buttonsPanel.add(createButtonsPanel(leftActions, rootPane), BorderLayout.WEST); + } + if (rightActions.size() > 0) { + buttonsPanel.add(createButtonsPanel(rightActions, rootPane), BorderLayout.EAST); + } + + myButtonsPanel.setContent(buttonsPanel); + } + + @NotNull + private static JPanel createButtonsPanel(@NotNull List actions, @Nullable JRootPane rootPane) { + List buttons = ContainerUtil.map(actions, action -> DialogWrapper.createJButtonForAction(action, rootPane)); + return DialogWrapper.layoutButtonsPanel(buttons); } @NotNull @@ -151,12 +233,14 @@ public abstract class MergeRequestProcessor implements Disposable { DiffUtil.addActionBlock(group, viewerActions); - List requestContextActions = myRequest.getUserData(DiffUserDataKeys.CONTEXT_ACTIONS); + List requestContextActions = myRequest != null ? myRequest.getUserData(DiffUserDataKeys.CONTEXT_ACTIONS) : null; DiffUtil.addActionBlock(group, requestContextActions); List contextActions = myContext.getUserData(DiffUserDataKeys.CONTEXT_ACTIONS); DiffUtil.addActionBlock(group, contextActions); + DiffUtil.addActionBlock(group, ActionManager.getInstance().getAction(IdeActions.ACTION_CONTEXT_HELP)); + return group; } @@ -173,10 +257,10 @@ public abstract class MergeRequestProcessor implements Disposable { } @NotNull - private MergeTool getFittedTool() { + private MergeTool getFittedTool(@NotNull MergeRequest request) { for (MergeTool tool : myAvailableTools) { try { - if (tool.canShow(myContext, myRequest)) return tool; + if (tool.canShow(myContext, request)) return tool; } catch (Throwable e) { LOG.error(e); @@ -191,6 +275,34 @@ public abstract class MergeRequestProcessor implements Disposable { setWindowTitle(title); } + private void installCallbackListener(@NotNull MergeRequest request) { + MergeCallback callback = MergeCallback.getCallback(request); + callback.addListener(new MergeCallback.Listener() { + @Override + public void fireConflictInvalid() { + showInvalidRequestNotification(); + } + }, this); + + if (!callback.checkIsValid()) { + showInvalidRequestNotification(); + } + } + + private void showInvalidRequestNotification() { + if (!myNotificationPanel.isNull()) return; + + EditorNotificationPanel notification = new EditorNotificationPanel(LightColors.RED); + notification.setText("Conflict is not valid and no longer can be resolved."); + notification.createActionLabel("Abort Resolve", () -> { + applyRequestResult(MergeResult.CANCEL); + closeDialog(); + }); + myNotificationPanel.setContent(notification); + myMainPanel.validate(); + myMainPanel.repaint(); + } + @Override public void dispose() { if (myDisposed) return; @@ -207,7 +319,7 @@ public abstract class MergeRequestProcessor implements Disposable { @CalledInAwt private void applyRequestResult(@NotNull MergeResult result) { - if (myConflictResolved) return; + if (myConflictResolved || myRequest == null) return; myConflictResolved = true; try { myRequest.applyResult(result); @@ -220,6 +332,7 @@ public abstract class MergeRequestProcessor implements Disposable { @CalledInAwt private void reopenWithTool(@NotNull MergeTool tool) { + if (myRequest == null) return; if (myConflictResolved) { LOG.warn("Can't reopen with " + tool + " - conflict already resolved"); return; @@ -239,11 +352,13 @@ public abstract class MergeRequestProcessor implements Disposable { return; } + swapViewer(newViewer); + } + + private void swapViewer(@NotNull MergeTool.MergeViewer newViewer) { DiffUtil.runPreservingFocus(myContext, () -> { destroyViewer(); myViewer = newViewer; - updateBottomActions(); - rebuildSouthPanel(); initViewer(); }); } @@ -259,10 +374,11 @@ public abstract class MergeRequestProcessor implements Disposable { protected void setWindowTitle(@NotNull String title) { } - protected abstract void rebuildSouthPanel(); - public abstract void closeDialog(); + @Nullable + protected abstract JRootPane getRootPane(); + @Nullable public T getContextUserData(@NotNull Key key) { return myContext.getUserData(key); @@ -302,16 +418,6 @@ public abstract class MergeRequestProcessor implements Disposable { return myConflictResolved || myCloseHandler == null || myCloseHandler.get(); } - @NotNull - public BottomActions getBottomActions() { - return myBottomActions != null ? myBottomActions : new BottomActions(); - } - - @Nullable - public String getHelpId() { - return PlatformDataKeys.HELP_ID.getData(myMainPanel); - } - // // Misc // @@ -404,7 +510,7 @@ public abstract class MergeRequestProcessor implements Disposable { return myProject; } else if (PlatformDataKeys.HELP_ID.is(dataId)) { - if (myRequest.getUserData(DiffUserDataKeys.HELP_ID) != null) { + if (myRequest != null && myRequest.getUserData(DiffUserDataKeys.HELP_ID) != null) { return myRequest.getUserData(DiffUserDataKeys.HELP_ID); } else { @@ -415,7 +521,7 @@ public abstract class MergeRequestProcessor implements Disposable { return myViewer; } - DataProvider requestProvider = myRequest.getUserData(DiffUserDataKeys.DATA_PROVIDER); + DataProvider requestProvider = myRequest != null ? myRequest.getUserData(DiffUserDataKeys.DATA_PROVIDER) : null; if (requestProvider != null) { data = requestProvider.getData(dataId); if (data != null) return data; @@ -468,11 +574,4 @@ public abstract class MergeRequestProcessor implements Disposable { MergeRequestProcessor.this.reopenWithTool(tool); } } - - public static class BottomActions { - @Nullable public Action applyLeft; - @Nullable public Action applyRight; - @Nullable public Action resolveAction; - @Nullable public Action cancelAction; - } } diff --git a/platform/diff-impl/src/com/intellij/diff/merge/MergeUtil.java b/platform/diff-impl/src/com/intellij/diff/merge/MergeUtil.java index d943c09d8c6d..db0e29252087 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/MergeUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/MergeUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.diff.merge; +import com.intellij.configurationStore.StoreReloadManager; import com.intellij.diff.DiffContext; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.merge.MergeTool.MergeViewer; @@ -34,6 +35,8 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.merge.MergeData; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.projectImport.ProjectOpenProcessor; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -43,6 +46,8 @@ import javax.swing.*; import java.awt.event.ActionEvent; import java.util.List; +import static com.intellij.openapi.project.ProjectUtil.isProjectOrWorkspaceFile; + public class MergeUtil { @NotNull public static Action createSimpleResolveAction(@NotNull MergeResult result, @@ -63,7 +68,7 @@ public class MergeUtil { } @NotNull - public static String getResolveActionTitle(@NotNull MergeResult result, @NotNull MergeRequest request, @NotNull MergeContext context) { + public static String getResolveActionTitle(@NotNull MergeResult result, @Nullable MergeRequest request, @Nullable MergeContext context) { Function getter = DiffUtil.getUserData(request, context, DiffUserDataKeysEx.MERGE_ACTION_CAPTIONS); String message = getter != null ? getter.fun(result) : null; if (message != null) return message; @@ -156,6 +161,14 @@ public class MergeUtil { return Messages.showYesNoDialog(component.getRootPane(), message, title, Messages.getQuestionIcon()) == Messages.YES; } + public static boolean shouldRestoreOriginalContentOnCancel(@NotNull MergeRequest request) { + MergeCallback callback = MergeCallback.getCallback(request); + if (callback.checkIsValid()) return true; + return Messages.showYesNoDialog("Merge conflict is outdated. Restore file content prior to conflict resolve start?", + DiffBundle.message("cancel.visual.merge.dialog.title"), "Restore", "Do nothing", + Messages.getQuestionIcon()) == Messages.YES; + } + public static void putRevisionInfos(@NotNull MergeRequest request, @NotNull MergeData data) { if (request instanceof ThreesideMergeRequest) { List contents = ((ThreesideMergeRequest)request).getContents(); @@ -182,4 +195,18 @@ public class MergeUtil { } } } + + public static void reportProjectFileChangeIfNeeded(@Nullable Project project, @Nullable VirtualFile file) { + if (project != null && file != null && isProjectFile(file)) { + StoreReloadManager.getInstance().saveChangedProjectFile(file, project); + } + } + + private static boolean isProjectFile(@NotNull VirtualFile file) { + if (file.isDirectory()) return false; + if (isProjectOrWorkspaceFile(file)) return true; + + ProjectOpenProcessor importProvider = ProjectOpenProcessor.getImportProvider(file); + return importProvider != null && importProvider.lookForProjectsInDirectory(); + } } diff --git a/platform/diff-impl/src/com/intellij/diff/merge/MergeWindow.java b/platform/diff-impl/src/com/intellij/diff/merge/MergeWindow.java index ff9ac360ce54..646e9a4f8675 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/MergeWindow.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/MergeWindow.java @@ -15,57 +15,58 @@ */ package com.intellij.diff.merge; +import com.intellij.diff.DiffDialogHints; import com.intellij.diff.util.DiffUserDataKeys; import com.intellij.diff.util.DiffUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.WindowWrapper; +import com.intellij.openapi.ui.WindowWrapperBuilder; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.components.panels.Wrapper; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.UIUtil; +import com.intellij.util.Consumer; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.util.List; -public class MergeWindow { +public abstract class MergeWindow { private static final Logger LOG = Logger.getInstance(MergeWindow.class); @Nullable private final Project myProject; - @NotNull private final MergeRequest myMergeRequest; + @NotNull private final DiffDialogHints myHints; - private MyDialog myWrapper; + private MergeRequestProcessor myProcessor; + private WindowWrapper myWrapper; - public MergeWindow(@Nullable Project project, @NotNull MergeRequest mergeRequest) { + public MergeWindow(@Nullable Project project, @NotNull DiffDialogHints hints) { myProject = project; - myMergeRequest = mergeRequest; + myHints = hints; } protected void init() { - MergeRequestProcessor processor = new MergeRequestProcessor(myProject, myMergeRequest) { - @Override - public void closeDialog() { - myWrapper.doCancelAction(); - } + if (myWrapper != null) return; - @Override - protected void setWindowTitle(@NotNull String title) { - myWrapper.setTitle(title); - } + myProcessor = createProcessor(); - @Override - protected void rebuildSouthPanel() { - myWrapper.rebuildSouthPanel(); - } - }; + String dialogGroupKey = myProcessor.getContextUserData(DiffUserDataKeys.DIALOG_GROUP_KEY); + if (dialogGroupKey == null) dialogGroupKey = "MergeDialog"; - myWrapper = new MyDialog(processor); - myWrapper.init(); + myWrapper = new WindowWrapperBuilder(DiffUtil.getWindowMode(myHints), new MyPanel(myProcessor.getComponent())) + .setProject(myProject) + .setParent(myHints.getParent()) + .setDimensionServiceKey(dialogGroupKey) + .setPreferredFocusedComponent(() -> myProcessor.getPreferredFocusedComponent()) + .setOnShowCallback(() -> initProcessor(myProcessor)) + .setOnCloseHandler(() -> myProcessor.checkCloseAction()) + .build(); + myWrapper.setImages(DiffUtil.DIFF_FRAME_ICONS); + Disposer.register(myWrapper, myProcessor); + + Consumer wrapperHandler = myHints.getWindowConsumer(); + if (wrapperHandler != null) wrapperHandler.consume(myWrapper); } public void show() { @@ -77,100 +78,30 @@ public class MergeWindow { myWrapper.show(); } - // TODO: use WindowWrapper - private static class MyDialog extends DialogWrapper { - @NotNull private final MergeRequestProcessor myProcessor; - @NotNull private final Wrapper mySouthPanel = new Wrapper(); - - MyDialog(@NotNull MergeRequestProcessor processor) { - super(processor.getProject(), true); - myProcessor = processor; - } - - @Override - public void init() { - super.init(); - Disposer.register(getDisposable(), myProcessor); - UIUtil.runWhenWindowOpened(getWindow(), () -> myProcessor.init()); - } - - @Nullable - @Override - protected JComponent createCenterPanel() { - return new MyPanel(myProcessor.getComponent()); - } - - @Nullable - @Override - protected JComponent createSouthPanel() { - rebuildSouthPanel(); - return mySouthPanel; - } - - @Nullable - @Override - public JComponent getPreferredFocusedComponent() { - return myProcessor.getPreferredFocusedComponent(); - } - - @Nullable - @Override - protected String getDimensionServiceKey() { - return StringUtil.notNullize(myProcessor.getContextUserData(DiffUserDataKeys.DIALOG_GROUP_KEY), "MergeDialog"); - } - - @NotNull - @Override - protected Action[] createActions() { - MergeRequestProcessor.BottomActions bottomActions = myProcessor.getBottomActions(); - List actions = ContainerUtil.skipNulls(ContainerUtil.list(bottomActions.resolveAction, bottomActions.cancelAction)); - if (bottomActions.resolveAction != null) { - bottomActions.resolveAction.putValue(DialogWrapper.DEFAULT_ACTION, true); + @NotNull + private MergeRequestProcessor createProcessor() { + return new MergeRequestProcessor(myProject) { + @Override + public void closeDialog() { + myWrapper.close(); } - return actions.toArray(new Action[0]); - } - @NotNull - @Override - protected Action[] createLeftSideActions() { - MergeRequestProcessor.BottomActions bottomActions = myProcessor.getBottomActions(); - List actions = ContainerUtil.skipNulls(ContainerUtil.list(bottomActions.applyLeft, bottomActions.applyRight)); - return actions.toArray(new Action[0]); - } + @Override + protected void setWindowTitle(@NotNull String title) { + myWrapper.setTitle(title); + } - @NotNull - @Override - protected Action getOKAction() { - MergeRequestProcessor.BottomActions bottomActions = myProcessor.getBottomActions(); - if (bottomActions.resolveAction != null) return bottomActions.resolveAction; - return super.getOKAction(); - } - - @NotNull - @Override - protected Action getCancelAction() { - MergeRequestProcessor.BottomActions bottomActions = myProcessor.getBottomActions(); - if (bottomActions.cancelAction != null) return bottomActions.cancelAction; - return super.getCancelAction(); - } - - @Nullable - @Override - protected String getHelpId() { - return myProcessor.getHelpId(); - } - - @Override - public void doCancelAction() { - if (!myProcessor.checkCloseAction()) return; - super.doCancelAction(); - } - - public void rebuildSouthPanel() { - mySouthPanel.setContent(super.createSouthPanel()); - } + @Nullable + @Override + protected JRootPane getRootPane() { + RootPaneContainer container = ObjectUtils.tryCast(myWrapper.getWindow(), RootPaneContainer.class); + return container != null ? container.getRootPane() : null; + } + }; } + protected abstract void initProcessor(@NotNull MergeRequestProcessor processor); + private static class MyPanel extends JPanel { MyPanel(@NotNull JComponent content) { super(new BorderLayout()); @@ -184,4 +115,34 @@ public class MergeWindow { return new Dimension(Math.max(windowSize.width, size.width), Math.max(windowSize.height, size.height)); } } + + public static class ForRequest extends MergeWindow { + @NotNull private final MergeRequest myMergeRequest; + + public ForRequest(@Nullable Project project, @NotNull MergeRequest mergeRequest, @NotNull DiffDialogHints hints) { + super(project, hints); + myMergeRequest = mergeRequest; + } + + + @Override + protected void initProcessor(@NotNull MergeRequestProcessor processor) { + processor.init(myMergeRequest); + } + } + + public static class ForProducer extends MergeWindow { + @NotNull private final MergeRequestProducer myMergeRequestProducer; + + public ForProducer(@Nullable Project project, @NotNull MergeRequestProducer mergeRequestProducer, @NotNull DiffDialogHints hints) { + super(project, hints); + myMergeRequestProducer = mergeRequestProducer; + } + + + @Override + protected void initProcessor(@NotNull MergeRequestProcessor processor) { + processor.init(myMergeRequestProducer); + } + } } diff --git a/platform/diff-impl/src/com/intellij/diff/merge/MessageMergeViewer.java b/platform/diff-impl/src/com/intellij/diff/merge/MessageMergeViewer.java new file mode 100644 index 000000000000..7a563b3f088c --- /dev/null +++ b/platform/diff-impl/src/com/intellij/diff/merge/MessageMergeViewer.java @@ -0,0 +1,59 @@ +// Copyright 2000-2019 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. +package com.intellij.diff.merge; + +import com.intellij.diff.util.DiffUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; + +class MessageMergeViewer implements MergeTool.MergeViewer { + @NotNull private final MergeContext myMergeContext; + + @NotNull private final JPanel myPanel; + + MessageMergeViewer(@NotNull MergeContext context, @NotNull String message) { + myMergeContext = context; + + myPanel = new JPanel(new BorderLayout()); + myPanel.add(DiffUtil.createMessagePanel(message), BorderLayout.CENTER); + } + + @NotNull + @Override + public JComponent getComponent() { + return myPanel; + } + + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return null; + } + + @NotNull + @Override + public MergeTool.ToolbarComponents init() { + return new MergeTool.ToolbarComponents(); + } + + @Nullable + @Override + public Action getResolveAction(@NotNull final MergeResult result) { + if (result != MergeResult.CANCEL) return null; + + String caption = MergeUtil.getResolveActionTitle(result, null, myMergeContext); + return new AbstractAction(caption) { + @Override + public void actionPerformed(ActionEvent e) { + myMergeContext.finishMerge(result); + } + }; + } + + @Override + public void dispose() { + } +} diff --git a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java index 2d019cf521c1..4a3566cece21 100644 --- a/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/merge/TextMergeViewer.java @@ -30,6 +30,7 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.diff.DiffBundle; @@ -43,7 +44,6 @@ import com.intellij.openapi.editor.markup.MarkupEditorFilter; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; import com.intellij.openapi.progress.util.BackgroundTaskUtil; import com.intellij.openapi.progress.util.ProgressWindow; import com.intellij.openapi.project.DumbAware; @@ -80,6 +80,11 @@ public class TextMergeViewer implements MergeTool.MergeViewer { @NotNull private final MyThreesideViewer myViewer; + private final Action myCancelResolveAction; + private final Action myLeftResolveAction; + private final Action myRightResolveAction; + private final Action myAcceptResolveAction; + public TextMergeViewer(@NotNull MergeContext context, @NotNull TextMergeRequest request) { myMergeContext = context; myMergeRequest = request; @@ -91,6 +96,11 @@ public class TextMergeViewer implements MergeTool.MergeViewer { diffRequest.putUserData(DiffUserDataKeys.FORCE_READ_ONLY_CONTENTS, new boolean[]{true, false, true}); myViewer = new MyThreesideViewer(diffContext, diffRequest); + + myCancelResolveAction = myViewer.getResolveAction(MergeResult.CANCEL); + myLeftResolveAction = myViewer.getResolveAction(MergeResult.LEFT); + myRightResolveAction = myViewer.getResolveAction(MergeResult.RIGHT); + myAcceptResolveAction = myViewer.getResolveAction(MergeResult.RESOLVED); } @NotNull @@ -145,7 +155,18 @@ public class TextMergeViewer implements MergeTool.MergeViewer { @Nullable @Override public Action getResolveAction(@NotNull MergeResult result) { - return myViewer.getResolveAction(result); + switch (result) { + case CANCEL: + return myCancelResolveAction; + case LEFT: + return myLeftResolveAction; + case RIGHT: + return myRightResolveAction; + case RESOLVED: + return myAcceptResolveAction; + default: + return null; + } } @Override @@ -383,34 +404,25 @@ public class TextMergeViewer implements MergeTool.MergeViewer { // This is made to reduce unwanted modifications before rediff is finished. // It could happen between this init() EDT chunk and invokeLater(). getEditor().setViewer(true); + myLoadingPanel.startLoading(); + myAcceptResolveAction.setEnabled(false); - // we need invokeLater() here because viewer is partially-initialized (ex: there are no toolbar or status panel) - // user can see this state while we're showing progress indicator, so we want let init() to finish. - ApplicationManager.getApplication().invokeLater(() -> ProgressManager.getInstance().run(new Task.Modal(getProject(), "Computing Differences...", true) { - private Runnable myCallback; + BackgroundTaskUtil.executeOnPooledThread(this, () -> { + ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - @Override - public void run(@NotNull ProgressIndicator indicator) { - myCallback = doPerformRediff(indicator); + Runnable callback; + try { + callback = doPerformRediff(indicator); } - - @Override - public void onCancel() { - myMergeContext.finishMerge(MergeResult.CANCEL); + catch (ProcessCanceledException e) { + callback = () -> myMergeContext.finishMerge(MergeResult.CANCEL); } - - @Override - public void onThrowable(@NotNull Throwable error) { - LOG.error(error); - myMergeContext.finishMerge(MergeResult.CANCEL); + catch (Throwable e) { + LOG.error(e); + callback = () -> myMergeContext.finishMerge(MergeResult.CANCEL); } - - @Override - public void onSuccess() { - if (isDisposed()) return; - myCallback.run(); - } - })); + ApplicationManager.getApplication().invokeLater(callback, ModalityState.stateForComponent(myPanel)); + }); } @NotNull @@ -453,6 +465,8 @@ public class TextMergeViewer implements MergeTool.MergeViewer { private void apply(@NotNull List fragments, @NotNull List conflictTypes, @NotNull IgnorePolicy ignorePolicy) { + if (isDisposed()) return; + clearDiffPresentation(); resetChangeCounters(); @@ -481,6 +495,8 @@ public class TextMergeViewer implements MergeTool.MergeViewer { myStatusPanel.update(); getEditor().setViewer(false); + myLoadingPanel.stopLoading(); + myAcceptResolveAction.setEnabled(true); myInnerDiffWorker.onEverythingChanged(); myInitialRediffFinished = true; @@ -676,7 +692,7 @@ public class TextMergeViewer implements MergeTool.MergeViewer { String message = DiffBundle.message("merge.all.changes.processed.message.text"); DiffUtil.showSuccessPopup(message, point, this, () -> { - if (isDisposed()) return; + if (isDisposed() || myLoadingPanel.isLoading()) return; destroyChangedBlocks(); myMergeContext.finishMerge(MergeResult.RESOLVED); }); diff --git a/platform/diff-impl/src/com/intellij/diff/requests/BinaryMergeRequestImpl.java b/platform/diff-impl/src/com/intellij/diff/requests/BinaryMergeRequestImpl.java index 6e09badee659..dd54bd422acb 100644 --- a/platform/diff-impl/src/com/intellij/diff/requests/BinaryMergeRequestImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/requests/BinaryMergeRequestImpl.java @@ -19,7 +19,9 @@ import com.intellij.CommonBundle; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.FileContent; import com.intellij.diff.merge.BinaryMergeRequest; +import com.intellij.diff.merge.MergeCallback; import com.intellij.diff.merge.MergeResult; +import com.intellij.diff.merge.MergeUtil; import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.ThreeSide; import com.intellij.openapi.command.WriteCommandAction; @@ -27,7 +29,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,16 +48,13 @@ public class BinaryMergeRequestImpl extends BinaryMergeRequest { @Nullable private final String myTitle; @NotNull private final List myTitles; - @Nullable private final Consumer myApplyCallback; - public BinaryMergeRequestImpl(@Nullable Project project, @NotNull FileContent file, @NotNull byte[] originalContent, @NotNull List contents, @NotNull List byteContents, @Nullable String title, - @NotNull List contentTitles, - @Nullable Consumer applyCallback) { + @NotNull List contentTitles) { assert byteContents.size() == 3; assert contents.size() == 3; assert contentTitles.size() == 3; @@ -70,8 +68,6 @@ public class BinaryMergeRequestImpl extends BinaryMergeRequest { myTitle = title; myTitles = contentTitles; - myApplyCallback = applyCallback; - onAssigned(true); } @@ -111,7 +107,7 @@ public class BinaryMergeRequestImpl extends BinaryMergeRequest { final byte[] applyContent; switch (result) { case CANCEL: - applyContent = myOriginalContent; + applyContent = MergeUtil.shouldRestoreOriginalContentOnCancel(this) ? myOriginalContent : null; break; case LEFT: applyContent = ThreeSide.LEFT.select(myByteContents); @@ -140,7 +136,7 @@ public class BinaryMergeRequestImpl extends BinaryMergeRequest { }); } - if (myApplyCallback != null) myApplyCallback.consume(result); + MergeCallback.getCallback(this).applyResult(result); } finally { onAssigned(false); diff --git a/platform/diff-impl/src/com/intellij/diff/requests/TextMergeRequestImpl.java b/platform/diff-impl/src/com/intellij/diff/requests/TextMergeRequestImpl.java index 104b1945ee16..e392c199ee5d 100644 --- a/platform/diff-impl/src/com/intellij/diff/requests/TextMergeRequestImpl.java +++ b/platform/diff-impl/src/com/intellij/diff/requests/TextMergeRequestImpl.java @@ -16,13 +16,14 @@ package com.intellij.diff.requests; import com.intellij.diff.contents.DocumentContent; +import com.intellij.diff.merge.MergeCallback; import com.intellij.diff.merge.MergeResult; +import com.intellij.diff.merge.MergeUtil; import com.intellij.diff.merge.TextMergeRequest; import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.ThreeSide; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,15 +39,12 @@ public class TextMergeRequestImpl extends TextMergeRequest { @Nullable private final String myTitle; @NotNull private final List myTitles; - @Nullable private final Consumer myApplyCallback; - public TextMergeRequestImpl(@Nullable Project project, @NotNull DocumentContent output, @NotNull CharSequence originalContent, @NotNull List contents, @Nullable String title, - @NotNull List contentTitles, - @Nullable Consumer applyCallback) { + @NotNull List contentTitles) { assert contents.size() == 3; assert contentTitles.size() == 3; myProject = project; @@ -58,8 +56,6 @@ public class TextMergeRequestImpl extends TextMergeRequest { myTitles = contentTitles; myTitle = title; - myApplyCallback = applyCallback; - onAssigned(true); } @@ -93,7 +89,7 @@ public class TextMergeRequestImpl extends TextMergeRequest { final CharSequence applyContent; switch (result) { case CANCEL: - applyContent = myOriginalContent; + applyContent = MergeUtil.shouldRestoreOriginalContentOnCancel(this) ? myOriginalContent : null; break; case LEFT: CharSequence leftContent = ThreeSide.LEFT.select(getContents()).getDocument().getImmutableCharSequence(); @@ -114,7 +110,7 @@ public class TextMergeRequestImpl extends TextMergeRequest { DiffUtil.executeWriteCommand(myOutput.getDocument(), myProject, null, () -> myOutput.getDocument().setText(applyContent)); } - if (myApplyCallback != null) myApplyCallback.consume(result); + MergeCallback.getCallback(this).applyResult(result); } finally { onAssigned(false); diff --git a/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffTool.java b/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffTool.java index 58438b1278bf..b5325c669cea 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffTool.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffTool.java @@ -28,14 +28,11 @@ import com.intellij.openapi.ListSelection; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.ThrowableConvertor; +import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -88,7 +85,7 @@ public class ExternalDiffTool { private static List loadRequestsUnderProgress(@Nullable Project project, @NotNull DiffRequestChain chain) throws Throwable { if (chain instanceof AsyncDiffRequestChain) { - return loadInBackground(project, "Loading Requests", indicator -> { + return VcsUtil.computeWithModalProgress(project, "Loading Requests", true, indicator -> { ListSelection listSelection = ((AsyncDiffRequestChain)chain).loadRequestsInBackground(); return collectRequests(project, listSelection.getList(), listSelection.getSelectedIndex(), indicator); }); @@ -97,7 +94,9 @@ public class ExternalDiffTool { List allProducers = chain.getRequests(); int index = chain.getIndex(); - return loadInBackground(project, "Loading Requests", indicator -> collectRequests(project, allProducers, index, indicator)); + return VcsUtil.computeWithModalProgress(project, "Loading Requests", true, indicator -> { + return collectRequests(project, allProducers, index, indicator); + }); } } @@ -162,28 +161,4 @@ public class ExternalDiffTool { } return true; } - - - @Nullable - private static T loadInBackground(@Nullable Project project, - @NotNull String title, - @NotNull ThrowableConvertor computable) throws Throwable { - final Ref requestsRef = new Ref<>(); - final Ref exceptionRef = new Ref<>(); - - ProgressManager.getInstance().run(new Task.Modal(project, title, true) { - @Override - public void run(@NotNull ProgressIndicator indicator) { - try { - requestsRef.set(computable.convert(indicator)); - } - catch (Throwable e) { - exceptionRef.set(e); - } - } - }); - - if (!exceptionRef.isNull()) throw exceptionRef.get(); - return requestsRef.get(); - } } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideDiffViewer.java index 4693a8310f62..0d3190b73d00 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideDiffViewer.java @@ -37,18 +37,21 @@ import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.util.Disposer; import com.intellij.pom.Navigatable; +import com.intellij.ui.components.JBLoadingPanel; import org.jetbrains.annotations.CalledInAwt; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.*; import java.util.ArrayList; import java.util.List; public abstract class ThreesideDiffViewer extends ListenerDiffViewerBase { @NotNull protected final SimpleDiffPanel myPanel; @NotNull protected final ThreesideContentPanel myContentPanel; + @NotNull protected final JBLoadingPanel myLoadingPanel; @NotNull private final List myHolders; @@ -63,7 +66,10 @@ public abstract class ThreesideDiffViewer extends Listen myFocusTrackerSupport = new FocusTrackerSupport.Threeside(myHolders); myContentPanel = new ThreesideContentPanel(myHolders, titlePanel); - myPanel = new SimpleDiffPanel(myContentPanel, this, context); + myLoadingPanel = new JBLoadingPanel(new BorderLayout(), this, 300); + myLoadingPanel.add(myContentPanel, BorderLayout.CENTER); + + myPanel = new SimpleDiffPanel(myLoadingPanel, this, context); } @Override diff --git a/platform/dvcs-impl/src/META-INF/dvcs.xml b/platform/dvcs-impl/src/META-INF/dvcs.xml index c408414ef181..8d43989226f1 100644 --- a/platform/dvcs-impl/src/META-INF/dvcs.xml +++ b/platform/dvcs-impl/src/META-INF/dvcs.xml @@ -7,6 +7,7 @@ + diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/repo/ClonePathProvider.java b/platform/dvcs-impl/src/com/intellij/dvcs/repo/ClonePathProvider.java new file mode 100644 index 000000000000..d282a615b990 --- /dev/null +++ b/platform/dvcs-impl/src/com/intellij/dvcs/repo/ClonePathProvider.java @@ -0,0 +1,63 @@ +// Copyright 2000-2019 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. +package com.intellij.dvcs.repo; + +import com.intellij.dvcs.DvcsRememberedInputs; +import com.intellij.ide.impl.ProjectUtil; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.util.PathUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.URLDecoder; + +/** + * Provides default paths for clone repository functionality. + * Default implementation suggests to clone a project to the `[project dir]/[last url component]`. + */ +public abstract class ClonePathProvider { + private static final ExtensionPointName EP_NAME = + ExtensionPointName.create("com.intellij.clonePathProvider"); + + @NotNull + public static String defaultParentDirectoryPath(@NotNull Project project, @NotNull DvcsRememberedInputs rememberedInputs) { + for (ClonePathProvider provider : EP_NAME.getExtensionList()) { + String directoryPath = provider.getParentDirectoryPath(project, rememberedInputs); + if (StringUtil.isNotEmpty(directoryPath)) { + return directoryPath; + } + } + + String parentDirectory = rememberedInputs.getCloneParentDir(); + return StringUtil.isEmptyOrSpaces(parentDirectory) ? ProjectUtil.getBaseDir() : parentDirectory; + } + + @NotNull + public static String relativeDirectoryPathForVcsUrl(@NotNull Project project, @NotNull String vcsUrl) { + for (ClonePathProvider provider : EP_NAME.getExtensionList()) { + String directoryPath = provider.getRelativeDirectoryPathForVcsUrl(project, vcsUrl); + if (StringUtil.isNotEmpty(directoryPath)) { + return directoryPath; + } + } + return safeUrlDecode(PathUtil.getFileName(vcsUrl)); + } + + @NotNull + private static String safeUrlDecode(@NotNull String encoded) { + try { + return URLDecoder.decode(encoded, CharsetToolkit.UTF8); + } + catch (Exception e) { + return encoded; + } + } + + @Nullable + public abstract String getParentDirectoryPath(@NotNull Project project, @NotNull DvcsRememberedInputs rememberedInputs); + + @Nullable + public abstract String getRelativeDirectoryPathForVcsUrl(@NotNull Project project, @NotNull String vcsUrl); +} diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java b/platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java index b2b4cac6cb2f..d36e53bd8071 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/ui/CloneDvcsDialog.java @@ -7,7 +7,7 @@ import com.intellij.dvcs.DvcsUtil; import com.intellij.dvcs.hosting.RepositoryHostingService; import com.intellij.dvcs.hosting.RepositoryListLoader; import com.intellij.dvcs.hosting.RepositoryListLoadingException; -import com.intellij.ide.impl.ProjectUtil; +import com.intellij.dvcs.repo.ClonePathProvider; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.IdeActions; @@ -30,7 +30,6 @@ import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.ui.*; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBOptionButton; @@ -51,11 +50,9 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; -import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLDecoder; import java.nio.file.*; import java.util.List; import java.util.*; @@ -181,8 +178,6 @@ public abstract class CloneDvcsDialog extends DialogWrapper { } private void initComponents(@Nullable String defaultUrl) { - String parentDirectory = getRememberedInputs().getCloneParentDir(); - myRepositoryUrlComboboxModel = new CollectionComboBoxModel<>(); myRepositoryUrlField = TextFieldWithAutoCompletion.create(myProject, myRepositoryUrlComboboxModel.getItems(), @@ -204,7 +199,7 @@ public abstract class CloneDvcsDialog extends DialogWrapper { myRepositoryUrlField.addDocumentListener(new DocumentListener() { @Override public void documentChanged(@NotNull com.intellij.openapi.editor.event.DocumentEvent event) { - myDirectoryField.trySetChildPath(defaultDirectoryName(myRepositoryUrlField.getText().trim())); + myDirectoryField.trySetChildPath(defaultDirectoryPath(myRepositoryUrlField.getText().trim())); } }); myRepositoryUrlField.addDocumentListener(new DocumentListener() { @@ -220,9 +215,7 @@ public abstract class CloneDvcsDialog extends DialogWrapper { FileChooserDescriptor fcd = FileChooserDescriptorFactory.createSingleFolderDescriptor(); fcd.setShowFileSystemRoots(true); fcd.setHideIgnored(false); - myDirectoryField = new MyTextFieldWithBrowseButton(StringUtil.isEmptyOrSpaces(parentDirectory) - ? ProjectUtil.getBaseDir() - : parentDirectory); + myDirectoryField = new MyTextFieldWithBrowseButton(ClonePathProvider.defaultParentDirectoryPath(myProject, getRememberedInputs())); myDirectoryField.addBrowseFolderListener(DvcsBundle.getString("clone.destination.directory.browser.title"), DvcsBundle.getString("clone.destination.directory.browser.description"), myProject, @@ -517,16 +510,6 @@ public abstract class CloneDvcsDialog extends DialogWrapper { rememberedInputs.setCloneParentDir(getParentDirectory()); } - @NotNull - private static String safeUrlDecode(@NotNull String encoded) { - try { - return URLDecoder.decode(encoded, CharsetToolkit.UTF8); - } - catch (Exception e) { - return encoded; - } - } - /** * Get default name for checked out directory * @@ -534,30 +517,8 @@ public abstract class CloneDvcsDialog extends DialogWrapper { * @return a default repository name */ @NotNull - private String defaultDirectoryName(@NotNull final String url) { - return stripSuffix(safeUrlDecode(getLastPathFragment(url))); - } - - @NotNull - private String stripSuffix(@NotNull String directoryName) { - return directoryName.endsWith(myVcsDirectoryName) - ? directoryName.substring(0, directoryName.length() - myVcsDirectoryName.length()) - : directoryName; - } - - @NotNull - private static String getLastPathFragment(@NotNull final String url) { - // Suppose it's a URL - int i = url.lastIndexOf('/'); - - // No? Maybe win-style path? - if (i == -1 && File.separatorChar != '/') i = url.lastIndexOf(File.separatorChar); - - if (i < 0) return ""; - - if (i == url.length() - 1) return getLastPathFragment(url.substring(0, i)); - - return url.substring(i + 1); + private String defaultDirectoryPath(@NotNull final String url) { + return StringUtil.trimEnd(ClonePathProvider.relativeDirectoryPathForVcsUrl(myProject, url), myVcsDirectoryName); } @Nullable diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemEventDispatcher.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemEventDispatcher.kt index 2f56c1ada679..c32dcfef2255 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemEventDispatcher.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemEventDispatcher.kt @@ -16,7 +16,7 @@ import java.io.Closeable */ @ApiStatus.Experimental class ExternalSystemEventDispatcher(task: ExternalSystemTask, - private val progressListener: BuildProgressListener?) : Closeable, Appendable, BuildProgressListener { + progressListener: BuildProgressListener?) : Closeable, Appendable, BuildProgressListener { private var outputMessageDispatcher: ExternalSystemOutputMessageDispatcher? = null init { @@ -37,8 +37,8 @@ class ExternalSystemEventDispatcher(task: ExternalSystemTask, foundFactory = it } } - outputMessageDispatcher = foundFactory?.create(task.getId(), progressListener, buildOutputParsers) - ?: DefaultOutputMessageDispatcher(task.getId(), progressListener, buildOutputParsers) + outputMessageDispatcher = foundFactory?.create(task.id, progressListener, buildOutputParsers) + ?: DefaultOutputMessageDispatcher(task.id, progressListener, buildOutputParsers) } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt index be59d7a0ca99..087e0da49c12 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt @@ -26,7 +26,6 @@ class SourceFolderManagerImpl(private val project: Project) : SourceFolderManage private var isDisposed = false private val mutex = Any() - private val postponedSourceFolderCreator = PostponedSourceFolderCreator() private val sourceFolders = PathPrefixTreeMapImpl() private val sourceFoldersByModule = THashMap() @@ -63,8 +62,6 @@ class SourceFolderManagerImpl(private val project: Project) : SourceFolderManage override fun dispose() { assert(!isDisposed) { "Source folder manager already disposed" } isDisposed = true - val virtualFileManager = VirtualFileManager.getInstance() - virtualFileManager.removeVirtualFileListener(postponedSourceFolderCreator) } fun isDisposed() = isDisposed @@ -131,6 +128,6 @@ class SourceFolderManagerImpl(private val project: Project) : SourceFolderManage init { val virtualFileManager = VirtualFileManager.getInstance() - virtualFileManager.addVirtualFileListener(postponedSourceFolderCreator, project) + virtualFileManager.addVirtualFileListener(PostponedSourceFolderCreator(), this) } } \ No newline at end of file diff --git a/platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java b/platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java index f2a9dcfeb97a..9e2fa4e09f72 100644 --- a/platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java +++ b/platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java @@ -16,6 +16,7 @@ package com.intellij.util.indexing; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ContentIterator; @@ -35,12 +36,13 @@ public abstract class IdFilter { private static final Key> INSIDE_PROJECT = Key.create("INSIDE_PROJECT"); private static final Key> OUTSIDE_PROJECT = Key.create("OUTSIDE_PROJECT"); - public static IdFilter getProjectIdFilter(final Project project, final boolean includeNonProjectItems) { + @NotNull + public static IdFilter getProjectIdFilter(@NotNull Project project, final boolean includeNonProjectItems) { Key> key = includeNonProjectItems ? OUTSIDE_PROJECT : INSIDE_PROJECT; + CachedValueProvider provider = () -> CachedValueProvider.Result.create(buildProjectIdFilter(project, includeNonProjectItems), + ProjectRootManager.getInstance(project), VirtualFileManager.VFS_STRUCTURE_MODIFICATIONS); return CachedValuesManager.getManager(project).getCachedValue(project, key, - () -> CachedValueProvider.Result - .create(buildProjectIdFilter(project, includeNonProjectItems), - ProjectRootManager.getInstance(project), VirtualFileManager.VFS_STRUCTURE_MODIFICATIONS), false); + provider, false); } @NotNull @@ -56,8 +58,9 @@ public abstract class IdFilter { if (!includeNonProjectItems) { ProjectRootManager.getInstance(project).getFileIndex().iterateContent(iterator); - } else { - FileBasedIndex.getInstance().iterateIndexableFiles(iterator, project, null); + } + else { + FileBasedIndex.getInstance().iterateIndexableFiles(iterator, project, ProgressIndicatorProvider.getGlobalProgressIndicator()); } if (LOG.isDebugEnabled()) { diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java b/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java index 0d223df3d8bd..bbec44cadbbf 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java @@ -193,23 +193,21 @@ public class LowLevelSearchUtil { FileViewProvider viewProvider, CharSequence buffer, TextRange range) { - StringBuilder msg = new StringBuilder() - .append("Range for element: '").append(scope).append("' = ").append(range) - .append(" is out of file '").append(file).append("' range: ").append(file.getTextRange()) - .append("; file contents length: ").append(buffer.length()) - .append("\n file provider: ").append(viewProvider); + String msg = "Range for element: '" + scope + "' = " + range + " is out of file '" + file + "' range: " + file.getTextRange(); + msg += "; file contents length: " + buffer.length(); + msg += "\n file provider: " + viewProvider; Document document = viewProvider.getDocument(); if (document != null) { - msg.append("\n committed=").append(PsiDocumentManager.getInstance(file.getProject()).isCommitted(document)); + msg += "\n committed=" + PsiDocumentManager.getInstance(file.getProject()).isCommitted(document); } for (Language language : viewProvider.getLanguages()) { final PsiFile root = viewProvider.getPsi(language); - msg.append("\n root ").append(language).append(" length=").append(root.getTextLength()); - if (root instanceof PsiFileImpl) { - msg.append("; contentsLoaded=").append(((PsiFileImpl)root).isContentsLoaded()); - } + //noinspection StringConcatenationInLoop + msg += "\n root " + language + " length=" + root.getTextLength() + (root instanceof PsiFileImpl + ? "; contentsLoaded=" + ((PsiFileImpl)root).isContentsLoaded() : ""); } - LOG.error(msg.toString()); + + LOG.error(msg); } // map (text to be scanned -> list of cached pairs of (searcher used to scan text, occurrences found)) diff --git a/platform/indexing-impl/src/com/intellij/psi/search/FileNameIndexService.java b/platform/indexing-impl/src/com/intellij/psi/search/FileNameIndexService.java index a1a2a7a3fe13..66917f80b498 100644 --- a/platform/indexing-impl/src/com/intellij/psi/search/FileNameIndexService.java +++ b/platform/indexing-impl/src/com/intellij/psi/search/FileNameIndexService.java @@ -29,7 +29,7 @@ interface FileNameIndexService { @NotNull Collection getVirtualFilesByName(Project project, @NotNull String name, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter); - void processAllFileNames(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter filter); + void processAllFileNames(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter filter); @NotNull Collection getFilesWithFileType(@NotNull FileType type, @NotNull GlobalSearchScope scope); diff --git a/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java b/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java index 0687c3eff0cc..7130c419e978 100644 --- a/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java @@ -56,7 +56,7 @@ public class FilenameIndex { return ArrayUtil.toStringArray(names); } - public static void processAllFileNames(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter filter) { + public static void processAllFileNames(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter filter) { getService().processAllFileNames(processor, scope, filter); } diff --git a/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/BraceStyleAccessor.java b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/BraceStyleAccessor.java index c704bf96a70f..f795d40d0033 100644 --- a/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/BraceStyleAccessor.java +++ b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/BraceStyleAccessor.java @@ -2,54 +2,29 @@ package com.intellij.application.options.codeStyle.properties; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; -import com.intellij.util.containers.BidirectionalMap; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; -class BraceStyleAccessor extends ExternalStringAccessor implements CodeStyleChoiceList { - private final static BidirectionalMap BRACE_STYLE_MAP = new BidirectionalMap<>(); - - public static final String VALUE_END_OF_LINE = "end_of_line"; - public static final String VALUE_NEXT_LINE = "next_line"; - public static final String VALUE_NEXT_LINE_IF_WRAPPED = "next_line_if_wrapped"; - public static final String VALUE_WHITESMITHS = "whitesmiths"; - public static final String VALUE_GNU = "gnu"; - - private final static List ALL_VALUES = - Arrays.asList(VALUE_END_OF_LINE, VALUE_NEXT_LINE, VALUE_NEXT_LINE_IF_WRAPPED, VALUE_WHITESMITHS, VALUE_GNU); - - static { - BRACE_STYLE_MAP.put(CommonCodeStyleSettings.END_OF_LINE, VALUE_END_OF_LINE); - BRACE_STYLE_MAP.put(CommonCodeStyleSettings.NEXT_LINE, VALUE_NEXT_LINE); - BRACE_STYLE_MAP.put(CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED, VALUE_NEXT_LINE_IF_WRAPPED); - BRACE_STYLE_MAP.put(CommonCodeStyleSettings.NEXT_LINE_SHIFTED, VALUE_WHITESMITHS); - BRACE_STYLE_MAP.put(CommonCodeStyleSettings.NEXT_LINE_SHIFTED2, VALUE_GNU); - } +class BraceStyleAccessor extends MagicIntegerConstAccessor { BraceStyleAccessor(@NotNull Object object, @NotNull Field field) { - super(object, field); + super(object, + field, + new int[]{ + CommonCodeStyleSettings.END_OF_LINE, + CommonCodeStyleSettings.NEXT_LINE, + CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED, + CommonCodeStyleSettings.NEXT_LINE_SHIFTED, + CommonCodeStyleSettings.NEXT_LINE_SHIFTED2 + }, + new String[]{ + "end_of_line", + "next_line", + "next_line_if_wrapped", + "whitesmiths", + "gnu" + }); } - @Nullable - @Override - protected Integer fromExternal(@NotNull String str) { - List keys = BRACE_STYLE_MAP.getKeysByValue(str); - return keys != null && keys.size() > 0 ? keys.get(0) : null; - } - - @NotNull - @Override - protected String toExternal(@NotNull Integer value) { - return BRACE_STYLE_MAP.get(value); - } - - @NotNull - @Override - public List getChoices() { - return ALL_VALUES; - } } diff --git a/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/FieldAccessorFactory.java b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/FieldAccessorFactory.java index 6d0dd2601894..fd693d735f00 100644 --- a/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/FieldAccessorFactory.java +++ b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/FieldAccessorFactory.java @@ -1,6 +1,7 @@ // 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. package com.intellij.application.options.codeStyle.properties; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings.BraceStyleConstant; import com.intellij.psi.codeStyle.CommonCodeStyleSettings.WrapConstant; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,7 +37,8 @@ class FieldAccessorFactory { if (wrapAnnotation != null) { return ValueType.WRAP; } - else if (fieldName.endsWith("BRACE_STYLE")) { + BraceStyleConstant braceAnnotation = myField.getAnnotation(BraceStyleConstant.class); + if (braceAnnotation != null) { return ValueType.BRACE_STYLE; } else if (fieldName.endsWith("_BRACE_FORCE")) { diff --git a/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/ForceBracesAccessor.java b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/ForceBracesAccessor.java index 73c07c7e4e24..f4ce69982cf2 100644 --- a/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/ForceBracesAccessor.java +++ b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/ForceBracesAccessor.java @@ -2,50 +2,24 @@ package com.intellij.application.options.codeStyle.properties; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; -import com.intellij.util.containers.BidirectionalMap; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; -class ForceBracesAccessor extends ExternalStringAccessor implements CodeStyleChoiceList { - - private final static BidirectionalMap FORCE_BRACES_MAP = new BidirectionalMap<>(); - - public static final String VALUE_NEVER = "never"; - public static final String VALUE_MULTILINE = "if_multiline"; - public static final String VALUE_ALWAYS = "always"; - - private final static List ALL_VALUES = Arrays.asList(VALUE_NEVER, VALUE_MULTILINE, VALUE_ALWAYS); - - static { - FORCE_BRACES_MAP.put(CommonCodeStyleSettings.DO_NOT_FORCE, VALUE_NEVER); - FORCE_BRACES_MAP.put(CommonCodeStyleSettings.FORCE_BRACES_IF_MULTILINE, VALUE_MULTILINE); - FORCE_BRACES_MAP.put(CommonCodeStyleSettings.FORCE_BRACES_ALWAYS, VALUE_ALWAYS); - } +class ForceBracesAccessor extends MagicIntegerConstAccessor { ForceBracesAccessor(@NotNull Object object, @NotNull Field field) { - super(object, field); - } - - @Nullable - @Override - protected Integer fromExternal(@NotNull String str) { - List keys = FORCE_BRACES_MAP.getKeysByValue(str); - return keys != null && keys.size() > 0 ? keys.get(0) : null; - } - - @NotNull - @Override - protected String toExternal(@NotNull Integer value) { - return FORCE_BRACES_MAP.get(value); - } - - @NotNull - @Override - public List getChoices() { - return ALL_VALUES; + super(object, + field, + new int[]{ + CommonCodeStyleSettings.DO_NOT_FORCE, + CommonCodeStyleSettings.FORCE_BRACES_IF_MULTILINE, + CommonCodeStyleSettings.FORCE_BRACES_ALWAYS + }, + new String[]{ + "never", + "if_multiline", + "always" + }); } } diff --git a/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/MagicIntegerConstAccessor.java b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/MagicIntegerConstAccessor.java new file mode 100644 index 000000000000..058e4de6ba28 --- /dev/null +++ b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/MagicIntegerConstAccessor.java @@ -0,0 +1,43 @@ +// Copyright 2000-2019 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. +package com.intellij.application.options.codeStyle.properties; + +import com.intellij.util.containers.BidirectionalMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +public class MagicIntegerConstAccessor extends ExternalStringAccessor implements CodeStyleChoiceList { + private final BidirectionalMap myValueMap = new BidirectionalMap<>(); + + public MagicIntegerConstAccessor(@NotNull Object object, + @NotNull Field field, + int[] intValues, + String[] strValues) { + super(object, field); + for (int i = 0; i < Math.min(intValues.length, strValues.length); i ++) { + myValueMap.put(intValues[i], strValues[i]); + } + } + + @Nullable + @Override + protected final Integer fromExternal(@NotNull String str) { + List keys = myValueMap.getKeysByValue(str); + return keys != null && keys.size() > 0 ? keys.get(0) : null; + } + + @NotNull + @Override + protected final String toExternal(@NotNull Integer value) { + return myValueMap.get(value); + } + + @NotNull + @Override + public final List getChoices() { + return new ArrayList<>(myValueMap.values()); + } +} diff --git a/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/WrappingAccessor.java b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/WrappingAccessor.java index 5b36127b0d7d..9dfd58cd9d0c 100644 --- a/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/WrappingAccessor.java +++ b/platform/lang-api/src/com/intellij/application/options/codeStyle/properties/WrappingAccessor.java @@ -2,53 +2,28 @@ package com.intellij.application.options.codeStyle.properties; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; -import com.intellij.util.containers.BidirectionalMap; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; -import java.util.List; -class WrappingAccessor extends ExternalStringAccessor implements CodeStyleChoiceList { - private final static BidirectionalMap WRAPPING_MAP = new BidirectionalMap<>(); - - public static final String VALUE_OFF = "off"; - public static final String VALUE_NORMAL = "normal"; - public static final String VALUE_ON_EVERY_ITEM = "on_every_item"; - public static final String VALUE_SPLIT_INTO_LINES = "split_into_lines"; - - public final static List ALL_VALUES = - ContainerUtil.immutableList(VALUE_OFF, VALUE_NORMAL, VALUE_ON_EVERY_ITEM, VALUE_SPLIT_INTO_LINES); - - static { - WRAPPING_MAP.put(CommonCodeStyleSettings.DO_NOT_WRAP, VALUE_OFF); - WRAPPING_MAP.put(CommonCodeStyleSettings.WRAP_AS_NEEDED, VALUE_NORMAL); - WRAPPING_MAP.put(CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM, VALUE_ON_EVERY_ITEM); - WRAPPING_MAP.put(CommonCodeStyleSettings.WRAP_AS_NEEDED | CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM, VALUE_ON_EVERY_ITEM); - WRAPPING_MAP.put(CommonCodeStyleSettings.WRAP_ALWAYS, VALUE_SPLIT_INTO_LINES); - } +class WrappingAccessor extends MagicIntegerConstAccessor { WrappingAccessor(@NotNull Object object, @NotNull Field field) { - super(object, field); + super(object, field, + new int[]{ + CommonCodeStyleSettings.DO_NOT_WRAP, + CommonCodeStyleSettings.WRAP_AS_NEEDED, + CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM, + CommonCodeStyleSettings.WRAP_AS_NEEDED | CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM, + CommonCodeStyleSettings.WRAP_ALWAYS + }, + new String[]{ + "off", + "normal", + "on_every_item", + "on_every_item", + "split_into_lines", + }); } - @Nullable - @Override - protected Integer fromExternal(@NotNull String str) { - List keys = WRAPPING_MAP.getKeysByValue(str); - return keys != null && keys.size() > 0 ? keys.get(0) : null; - } - - @NotNull - @Override - protected String toExternal(@NotNull Integer value) { - return WRAPPING_MAP.get(value); - } - - @NotNull - @Override - public List getChoices() { - return ALL_VALUES; - } } diff --git a/platform/lang-api/src/com/intellij/build/output/BuildOutputInstantReader.java b/platform/lang-api/src/com/intellij/build/output/BuildOutputInstantReader.java index 3c23241f76f9..ecec01938f91 100644 --- a/platform/lang-api/src/com/intellij/build/output/BuildOutputInstantReader.java +++ b/platform/lang-api/src/com/intellij/build/output/BuildOutputInstantReader.java @@ -2,6 +2,7 @@ package com.intellij.build.output; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -9,7 +10,8 @@ import org.jetbrains.annotations.Nullable; */ @ApiStatus.Experimental public interface BuildOutputInstantReader { - Object getBuildId(); + @NotNull + Object getParentEventId(); @Nullable String readLine(); diff --git a/platform/lang-api/src/com/intellij/build/output/BuildOutputParser.java b/platform/lang-api/src/com/intellij/build/output/BuildOutputParser.java index e624bbc0019a..242d5ff57640 100644 --- a/platform/lang-api/src/com/intellij/build/output/BuildOutputParser.java +++ b/platform/lang-api/src/com/intellij/build/output/BuildOutputParser.java @@ -2,7 +2,6 @@ package com.intellij.build.output; import com.intellij.build.events.BuildEvent; -import com.intellij.build.events.MessageEvent; import org.jetbrains.annotations.ApiStatus; import java.util.function.Consumer; diff --git a/platform/lang-api/src/com/intellij/codeInsight/editorActions/TabOutScopesTracker.java b/platform/lang-api/src/com/intellij/codeInsight/editorActions/TabOutScopesTracker.java index 814a69a3936a..9f61545f6ed7 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/editorActions/TabOutScopesTracker.java +++ b/platform/lang-api/src/com/intellij/codeInsight/editorActions/TabOutScopesTracker.java @@ -3,7 +3,6 @@ package com.intellij.codeInsight.editorActions; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.Editor; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; /** @@ -11,7 +10,6 @@ import org.jetbrains.annotations.NotNull; * quote/bracket) using Tab key. The scope is usually created (registered) when a pair of quotes/brackets is inserted into a document, and * lives until user 'tabs out' of this scope, or performs editing outside it. */ -@ApiStatus.Experimental public interface TabOutScopesTracker { static TabOutScopesTracker getInstance() { return ServiceManager.getService(TabOutScopesTracker.class); @@ -29,7 +27,16 @@ public interface TabOutScopesTracker { * Registers a new scope (empty at the time of call) at the given offset. Provided offset is supposed to point at the location between * just inserted pair of quotes/brackets. */ - void registerEmptyScope(@NotNull Editor editor, int offset); + default void registerEmptyScope(@NotNull Editor editor, int offset) { + registerEmptyScope(editor, offset, 1); + } + + /** + * Same as {@link #registerEmptyScope(Editor, int)} but allows to set custom caret shift on exiting the scope. This is for the cases when scope suffix contains more than one character (e.g. a closing parenthesis and a semicolon). + * + * @param caretShift a positive value, representing desired caret offset shift when Tab is used to exit the scope + */ + void registerEmptyScope(@NotNull Editor editor, int offset, int caretShift); /** * Checks whether given offset is at the end of tracked scope (so if caret is located at that offset, Tab key can be used to move out of @@ -40,9 +47,10 @@ public interface TabOutScopesTracker { /** * Removes a tracked scope (if any) ending at the given offset. * - * @return whether there was a scope ending at given offset + * @return a positive value indicating required caret shift, if there was a scope ending at given offset, and zero otherwise * * @see #hasScopeEndingAt(Editor, int) + * @see #registerEmptyScope(Editor, int, int) */ - boolean removeScopeEndingAt(@NotNull Editor editor, int offset); + int removeScopeEndingAt(@NotNull Editor editor, int offset); } diff --git a/platform/lang-api/src/com/intellij/formatting/Block.java b/platform/lang-api/src/com/intellij/formatting/Block.java index a8955603acc7..f4834d8658cc 100644 --- a/platform/lang-api/src/com/intellij/formatting/Block.java +++ b/platform/lang-api/src/com/intellij/formatting/Block.java @@ -39,6 +39,8 @@ public interface Block { * Returns the list of child blocks for the specified block. Important: The same list * of blocks must be returned when {@code getSubBlocks()} is repeatedly called on a particular * {@code Block} instance. + * Even more Important: + * If immutable list is returned (e.g. {@code Collections.singletonList(xxx)}, you must mark this {@link Block} class with {@link com.intellij.formatting.ReadOnlyBlockContainer} marker interface. * * @return the child block list. * @see #isLeaf() diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java index 59baf1d091d3..01271fd9a585 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java @@ -331,6 +331,7 @@ public class CommonCodeStyleSettings { public static final int NEXT_LINE_IF_WRAPPED = 5; @MagicConstant(intValues = {END_OF_LINE, NEXT_LINE, NEXT_LINE_SHIFTED, NEXT_LINE_SHIFTED2, NEXT_LINE_IF_WRAPPED}) + @Retention(RetentionPolicy.RUNTIME) public @interface BraceStyleConstant {} @BraceStyleConstant public int BRACE_STYLE = END_OF_LINE; diff --git a/platform/lang-impl/src/com/intellij/build/output/BuildOutputInstantReaderImpl.kt b/platform/lang-impl/src/com/intellij/build/output/BuildOutputInstantReaderImpl.kt index 86f7f247aac5..b0319db33570 100644 --- a/platform/lang-impl/src/com/intellij/build/output/BuildOutputInstantReaderImpl.kt +++ b/platform/lang-impl/src/com/intellij/build/output/BuildOutputInstantReaderImpl.kt @@ -17,7 +17,7 @@ import java.util.concurrent.Future /** * @author Vladislav.Soroka */ -open class BuildOutputInstantReaderImpl(private val buildId: Any, +open class BuildOutputInstantReaderImpl(private val parentEventId: Any, buildProgressListener: BuildProgressListener, parsers: List) : BuildOutputInstantReader, Closeable, Appendable { private val readJob: Job @@ -29,14 +29,14 @@ open class BuildOutputInstantReaderImpl(private val buildId: Any, private val appendedLineProcessor: LineProcessor init { - readJob = createReadJob(buildProgressListener, this, parsers) + readJob = createReadJob(buildProgressListener, parsers) val appendScope = CoroutineScope(Dispatchers.Default + appendParentJob) appendedLineProcessor = MyLineProcessor(readJob, appendScope, outputLinesChannel) } private fun createReadJob(buildProgressListener: BuildProgressListener, - reader: BuildOutputInstantReaderImpl, parsers: List): Job { + val thisReader: BuildOutputInstantReader = this return CoroutineScope(Dispatchers.Default).launch(start = CoroutineStart.LAZY) { var lastMessage: BuildEvent? = null val messageConsumer = { event: BuildEvent -> @@ -48,11 +48,11 @@ open class BuildOutputInstantReaderImpl(private val buildId: Any, } while (true) { - val line = reader.readLine() ?: break + val line = thisReader.readLine() ?: break if (line.isBlank()) continue for (parser in parsers) { - val readerWrapper = BuildOutputInstantReaderWrapper(reader) + val readerWrapper = BuildOutputInstantReaderWrapper(thisReader) if (parser.parse(line, readerWrapper, messageConsumer)) break readerWrapper.pushBackReadLines() } @@ -60,8 +60,8 @@ open class BuildOutputInstantReaderImpl(private val buildId: Any, } } - override fun getBuildId(): Any { - return buildId + override fun getParentEventId(): Any { + return parentEventId } override fun append(csq: CharSequence): BuildOutputInstantReaderImpl { @@ -146,10 +146,10 @@ open class BuildOutputInstantReaderImpl(private val buildId: Any, } } - private class BuildOutputInstantReaderWrapper(private val reader: BuildOutputInstantReaderImpl) : BuildOutputInstantReader { + private class BuildOutputInstantReaderWrapper(private val reader: BuildOutputInstantReader) : BuildOutputInstantReader { private var linesRead = 0 - override fun getBuildId(): Any = reader.buildId + override fun getParentEventId(): Any = reader.parentEventId override fun readLine(): String? { val line = reader.readLine() diff --git a/java/compiler/impl/src/com/intellij/build/output/JavacOutputParser.java b/platform/lang-impl/src/com/intellij/build/output/JavacOutputParser.java similarity index 90% rename from java/compiler/impl/src/com/intellij/build/output/JavacOutputParser.java rename to platform/lang-impl/src/com/intellij/build/output/JavacOutputParser.java index 52052ef7dc62..94bd72e05856 100644 --- a/java/compiler/impl/src/com/intellij/build/output/JavacOutputParser.java +++ b/platform/lang-impl/src/com/intellij/build/output/JavacOutputParser.java @@ -39,17 +39,17 @@ public class JavacOutputParser implements BuildOutputParser { if (part1.equalsIgnoreCase("error") /* jikes */ || part1.equalsIgnoreCase("Caused by")) { // +1 so we don't include the colon String text = line.substring(colonIndex1 + 1).trim(); - messageConsumer.accept(new MessageEventImpl(reader.getBuildId(), MessageEvent.Kind.ERROR, COMPILER_MESSAGES_GROUP, text, line)); + messageConsumer.accept(new MessageEventImpl(reader.getParentEventId(), MessageEvent.Kind.ERROR, COMPILER_MESSAGES_GROUP, text, line)); return true; } if (part1.equalsIgnoreCase("warning")) { // +1 so we don't include the colon String text = line.substring(colonIndex1 + 1).trim(); - messageConsumer.accept(new MessageEventImpl(reader.getBuildId(), MessageEvent.Kind.WARNING, COMPILER_MESSAGES_GROUP, text, line)); + messageConsumer.accept(new MessageEventImpl(reader.getParentEventId(), MessageEvent.Kind.WARNING, COMPILER_MESSAGES_GROUP, text, line)); return true; } if (part1.equalsIgnoreCase("javac")) { - messageConsumer.accept(new MessageEventImpl(reader.getBuildId(), MessageEvent.Kind.ERROR, COMPILER_MESSAGES_GROUP, line, line)); + messageConsumer.accept(new MessageEventImpl(reader.getParentEventId(), MessageEvent.Kind.ERROR, COMPILER_MESSAGES_GROUP, line, line)); return true; } if (part1.equalsIgnoreCase("Note")) { @@ -60,7 +60,7 @@ public class JavacOutputParser implements BuildOutputParser { if (file.isFile()) { message = message.substring(javaFileExtensionIndex + ".java".length() + 1); String detailedMessage = amendNextInfoLinesIfNeeded(file.getPath() + ":\n" + message, reader); - messageConsumer.accept(new FileMessageEventImpl(reader.getBuildId(), MessageEvent.Kind.INFO, COMPILER_MESSAGES_GROUP, + messageConsumer.accept(new FileMessageEventImpl(reader.getParentEventId(), MessageEvent.Kind.INFO, COMPILER_MESSAGES_GROUP, message, detailedMessage, new FilePosition(file, 0, 0))); return true; @@ -124,7 +124,7 @@ public class JavacOutputParser implements BuildOutputParser { if (column >= 0) { messageList = convertMessages(messageList); String msgText = StringUtil.join(messageList, SystemProperties.getLineSeparator()); - messageConsumer.accept(new FileMessageEventImpl(reader.getBuildId(), kind, COMPILER_MESSAGES_GROUP, msgText, msgText, + messageConsumer.accept(new FileMessageEventImpl(reader.getParentEventId(), kind, COMPILER_MESSAGES_GROUP, msgText, msgText, new FilePosition(file, lineNumber - 1, column))); return true; } @@ -135,7 +135,7 @@ public class JavacOutputParser implements BuildOutputParser { } if (line.endsWith("java.lang.OutOfMemoryError")) { - messageConsumer.accept(new MessageEventImpl(reader.getBuildId(), MessageEvent.Kind.ERROR, COMPILER_MESSAGES_GROUP, + messageConsumer.accept(new MessageEventImpl(reader.getParentEventId(), MessageEvent.Kind.ERROR, COMPILER_MESSAGES_GROUP, "Out of memory.", line)); return true; } diff --git a/java/compiler/impl/src/com/intellij/build/output/KotlincOutputParser.kt b/platform/lang-impl/src/com/intellij/build/output/KotlincOutputParser.kt similarity index 85% rename from java/compiler/impl/src/com/intellij/build/output/KotlincOutputParser.kt rename to platform/lang-impl/src/com/intellij/build/output/KotlincOutputParser.kt index 3c85188eba28..b694a1c072c5 100644 --- a/java/compiler/impl/src/com/intellij/build/output/KotlincOutputParser.kt +++ b/platform/lang-impl/src/com/intellij/build/output/KotlincOutputParser.kt @@ -1,4 +1,4 @@ -// 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-2019 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. package com.intellij.build.output import com.intellij.build.FilePosition @@ -37,7 +37,7 @@ class KotlincOutputParser : BuildOutputParser { val fileExtension = file.extension.toLowerCase() if (!file.isFile || (fileExtension != "kt" && fileExtension != "java")) { - return addMessage(createMessage(reader.buildId, getMessageKind(severity), lineWoSeverity.amendNextLinesIfNeeded(reader), line), + return addMessage(createMessage(reader.parentEventId, getMessageKind(severity), lineWoSeverity.amendNextLinesIfNeeded(reader), line), consumer) } @@ -57,15 +57,15 @@ class KotlincOutputParser : BuildOutputParser { if (lineNumber != null) { val symbolNumberText = symbolNumber.toInt() return addMessage(createMessageWithLocation( - reader.buildId, getMessageKind(severity), message, path, lineNumber.toInt(), symbolNumberText, details), consumer) + reader.parentEventId, getMessageKind(severity), message, path, lineNumber.toInt(), symbolNumberText, details), consumer) } } - return addMessage(createMessage(reader.buildId, getMessageKind(severity), message, details), consumer) + return addMessage(createMessage(reader.parentEventId, getMessageKind(severity), message, details), consumer) } else { val text = lineWoSeverity.amendNextLinesIfNeeded(reader) - return addMessage(createMessage(reader.buildId, getMessageKind(severity), text, text), consumer) + return addMessage(createMessage(reader.parentEventId, getMessageKind(severity), text, text), consumer) } } @@ -139,12 +139,12 @@ class KotlincOutputParser : BuildOutputParser { return true } - private fun createMessage(buildId: Any, messageKind: MessageEvent.Kind, text: String, detail: String): MessageEvent { - return MessageEventImpl(buildId, messageKind, COMPILER_MESSAGES_GROUP, text.trim(), detail) + private fun createMessage(parentId: Any, messageKind: MessageEvent.Kind, text: String, detail: String): MessageEvent { + return MessageEventImpl(parentId, messageKind, COMPILER_MESSAGES_GROUP, text.trim(), detail) } private fun createMessageWithLocation( - buildId: Any, + parentId: Any, messageKind: MessageEvent.Kind, text: String, file: String, @@ -152,7 +152,7 @@ class KotlincOutputParser : BuildOutputParser { columnIndex: Int, detail: String ): FileMessageEventImpl { - return FileMessageEventImpl(buildId, messageKind, COMPILER_MESSAGES_GROUP, text.trim(), detail, + return FileMessageEventImpl(parentId, messageKind, COMPILER_MESSAGES_GROUP, text.trim(), detail, FilePosition(File(file), lineNumber - 1, columnIndex - 1)) } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java index 0db7e4285de0..a77aec50a48e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -10,6 +10,7 @@ import com.intellij.icons.AllIcons; import com.intellij.ide.DataManager; import com.intellij.ide.actions.BaseNavigateToSourceAction; import com.intellij.ide.actions.ExternalJavaDocAction; +import com.intellij.ide.actions.WindowAction; import com.intellij.ide.util.PropertiesComponent; import com.intellij.lang.documentation.CompositeDocumentationProvider; import com.intellij.lang.documentation.DocumentationMarkup; @@ -17,11 +18,13 @@ import com.intellij.lang.documentation.DocumentationProvider; import com.intellij.lang.documentation.ExternalDocumentationHandler; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.AnActionListener; import com.intellij.openapi.actionSystem.impl.ActionButton; import com.intellij.openapi.actionSystem.impl.ActionManagerImpl; import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; import com.intellij.openapi.actionSystem.impl.MenuItemPresentationFactory; import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.editor.colors.EditorColorsManager; @@ -927,13 +930,21 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr AbstractPopup hint = myHint; if (hint == null || mySizeTrackerRegistered) return; mySizeTrackerRegistered = true; - hint.addResizeListener(() -> { - myManuallyResized = true; - if (myStoreSize) { - hint.setDimensionServiceKey(DocumentationManager.NEW_JAVADOC_LOCATION_AND_SIZE); - hint.storeDimensionSize(); + hint.addResizeListener(this::onManualResizing, this); + ApplicationManager.getApplication().getMessageBus().connect(this).subscribe(AnActionListener.TOPIC, new AnActionListener() { + @Override + public void afterActionPerformed(@NotNull AnAction action, @NotNull DataContext dataContext, @NotNull AnActionEvent event) { + if (action instanceof WindowAction) onManualResizing(); } - }, this); + }); + } + + private void onManualResizing() { + myManuallyResized = true; + if (myStoreSize && myHint != null) { + myHint.setDimensionServiceKey(DocumentationManager.NEW_JAVADOC_LOCATION_AND_SIZE); + myHint.storeDimensionSize(); + } } private int definitionPreferredWidth() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java index d5801d535783..40da18976ace 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -14,6 +14,7 @@ import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.ide.BrowserUtil; import com.intellij.ide.IdeEventQueue; import com.intellij.ide.actions.BaseNavigateToSourceAction; +import com.intellij.ide.actions.WindowAction; import com.intellij.ide.highlighter.ArchiveFileType; import com.intellij.ide.util.PropertiesComponent; import com.intellij.ide.util.gotoByName.ChooseByNameBase; @@ -104,7 +105,8 @@ public class DocumentationManager extends DockablePopupManager CARET_SHIFT = Key.create("tab.out.caret.shift"); + @Override - public void registerEmptyScope(@NotNull Editor editor, int offset) { + public void registerEmptyScope(@NotNull Editor editor, int offset, int caretShift) { ApplicationManager.getApplication().assertIsDispatchThread(); assert !editor.isDisposed() : "Disposed editor"; + assert caretShift > 0 : "Caret shift must be positive"; if (!CodeInsightSettings.getInstance().TAB_EXITS_BRACKETS_AND_QUOTES) return; @@ -37,35 +40,35 @@ public class TabOutScopesTrackerImpl implements TabOutScopesTracker { if (!(editor instanceof EditorImpl)) return; Tracker tracker = Tracker.forEditor((EditorImpl)editor, true); - tracker.registerScope(offset); + tracker.registerScope(offset, caretShift); } @Override public boolean hasScopeEndingAt(@NotNull Editor editor, int offset) { - return checkOrRemoveScopeEndingAt(editor, offset, false); + return checkOrRemoveScopeEndingAt(editor, offset, false) > 0; } @Override - public boolean removeScopeEndingAt(@NotNull Editor editor, int offset) { + public int removeScopeEndingAt(@NotNull Editor editor, int offset) { return checkOrRemoveScopeEndingAt(editor, offset, true); } - private static boolean checkOrRemoveScopeEndingAt(@NotNull Editor editor, int offset, boolean removeScope) { + private static int checkOrRemoveScopeEndingAt(@NotNull Editor editor, int offset, boolean removeScope) { ApplicationManager.getApplication().assertIsDispatchThread(); - if (!CodeInsightSettings.getInstance().TAB_EXITS_BRACKETS_AND_QUOTES) return false; + if (!CodeInsightSettings.getInstance().TAB_EXITS_BRACKETS_AND_QUOTES) return 0; if (editor instanceof EditorWindow) { DocumentWindow documentWindow = ((EditorWindow)editor).getDocument(); offset = documentWindow.injectedToHost(offset); editor = ((EditorWindow)editor).getDelegate(); } - if (!(editor instanceof EditorImpl)) return false; + if (!(editor instanceof EditorImpl)) return 0; Tracker tracker = Tracker.forEditor((EditorImpl)editor, false); - if (tracker == null) return false; + if (tracker == null) return 0; - return tracker.hasScopeEndingAt(offset, removeScope); + return tracker.getCaretShiftForScopeEndingAt(offset, removeScope); } private static class Tracker extends DocumentBulkUpdateListener.Adapter implements DocumentListener { @@ -98,24 +101,26 @@ public class TabOutScopesTrackerImpl implements TabOutScopesTracker { return result; } - private void registerScope(int offset) { + private void registerScope(int offset, int caretShift) { RangeMarker marker = myEditor.getDocument().createRangeMarker(offset, offset); marker.setGreedyToLeft(true); marker.setGreedyToRight(true); + if (caretShift > 1) marker.putUserData(CARET_SHIFT, caretShift); getCurrentScopes(true).add(marker); } - private boolean hasScopeEndingAt(int offset, boolean remove) { + private int getCaretShiftForScopeEndingAt(int offset, boolean remove) { List scopes = getCurrentScopes(false); - if (scopes == null) return false; + if (scopes == null) return 0; for (Iterator it = scopes.iterator(); it.hasNext(); ) { RangeMarker scope = it.next(); if (offset == scope.getEndOffset()) { if (remove) it.remove(); - return true; + Integer caretShift = scope.getUserData(CARET_SHIFT); + return caretShift == null ? 1 : caretShift; } } - return false; + return 0; } @Override diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java index 1969616f0c64..10cf42f351a0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java @@ -305,7 +305,7 @@ public class TemplateImpl extends Template implements SchemeElement { } mySegments = new SmartList<>(); - StringBuilder buffer = new StringBuilder(); + StringBuilder buffer = new StringBuilder(myString.length()); TemplateTextLexer lexer = new TemplateTextLexer(); lexer.start(myString); diff --git a/platform/lang-impl/src/com/intellij/extapi/psi/MetadataPsiElementBase.java b/platform/lang-impl/src/com/intellij/extapi/psi/MetadataPsiElementBase.java deleted file mode 100644 index be4b4424a805..000000000000 --- a/platform/lang-impl/src/com/intellij/extapi/psi/MetadataPsiElementBase.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.extapi.psi; - -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -@Deprecated -@ApiStatus.ScheduledForRemoval(inVersion = "2019.2") -public abstract class MetadataPsiElementBase extends PsiElementBase { - - private final PsiElement mySourceElement; - - public MetadataPsiElementBase(PsiElement sourceElement) { - mySourceElement = sourceElement; - } - - @Override - public TextRange getTextRange() { - return mySourceElement != null? mySourceElement.getTextRange() : null; - } - - @Override - public int getStartOffsetInParent() { - final PsiElement parent = getParent(); - return (parent == null) ? 0 : getTextRange().getStartOffset() - parent.getTextRange().getStartOffset(); - } - - @Override - public int getTextLength() { - return mySourceElement.getTextLength(); - } - - @Override - public int getTextOffset() { - return mySourceElement.getTextOffset(); - } - - @Override - public String getText() { - return mySourceElement.getText(); - } - - @Override - @NotNull - public char[] textToCharArray() { - return mySourceElement.textToCharArray(); - } - - @Override - public boolean textContains(char c) { - return mySourceElement.textContains(c); - } - - public PsiElement getSourceElement() { - return mySourceElement; - } -} diff --git a/platform/lang-impl/src/com/intellij/extapi/psi/PsiElementBase.java b/platform/lang-impl/src/com/intellij/extapi/psi/PsiElementBase.java deleted file mode 100644 index 5eb81451d5d6..000000000000 --- a/platform/lang-impl/src/com/intellij/extapi/psi/PsiElementBase.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.extapi.psi; - -import com.intellij.ide.util.PsiNavigationSupport; -import com.intellij.navigation.ItemPresentation; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.pom.Navigatable; -import com.intellij.psi.*; -import com.intellij.psi.impl.ElementBase; -import com.intellij.psi.impl.ResolveScopeManager; -import com.intellij.psi.impl.SharedPsiElementImplUtil; -import com.intellij.psi.scope.PsiScopeProcessor; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.SearchScope; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -/** - * @deprecated Please use {@link com.intellij.psi.impl.PsiElementBase} as a base class - * or one of its descendants, e.g. {@link ASTWrapperPsiElement}, as suggested in a - * tutorial - */ -@Deprecated -@ApiStatus.ScheduledForRemoval(inVersion = "2019.2") -public abstract class PsiElementBase extends ElementBase implements NavigatablePsiElement { - private static final Logger LOG = Logger.getInstance("#com.intellij.extapi.psi.PsiElementBase"); - - @Override - public PsiElement copy() { - return (PsiElement)clone(); - } - - @Override - public PsiElement add(@NotNull PsiElement element) throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public PsiElement addBefore(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public PsiElement addAfter(@NotNull PsiElement element, PsiElement anchor) throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public void checkAdd(@NotNull PsiElement element) throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public PsiElement addRange(PsiElement first, PsiElement last) throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public PsiElement addRangeBefore(@NotNull PsiElement first, @NotNull PsiElement last, PsiElement anchor) throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public PsiElement addRangeAfter(PsiElement first, PsiElement last, PsiElement anchor) throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public void delete() throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public void checkDelete() throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public void deleteChildRange(PsiElement first, PsiElement last) throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public PsiElement replace(@NotNull PsiElement newElement) throws IncorrectOperationException { - throw new UnsupportedOperationException(getClass().getName()); - } - - @Override - public PsiReference getReference() { - return null; - } - - @Override - public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { - return true; - } - - @Override - @NotNull - public Project getProject() { - final PsiManager manager = getManager(); - if (manager == null) { - throw new PsiInvalidElementAccessException(this); - } - - return manager.getProject(); - } - - @Override - public PsiManager getManager() { - final PsiElement parent = getParent(); - return parent != null ? parent.getManager() : null; - } - - @Override - public PsiFile getContainingFile() { - final PsiElement parent = getParent(); - if (parent == null) throw new PsiInvalidElementAccessException(this); - return parent.getContainingFile(); - } - - @Override - public PsiReference findReferenceAt(int offset) { - return SharedPsiElementImplUtil.findReferenceAt(this, offset); - } - - @Override - @NotNull - public PsiElement getNavigationElement() { - return this; - } - - @Override - public PsiElement getOriginalElement() { - return this; - } - - //Q: get rid of these methods? - @Override - public boolean textMatches(@NotNull CharSequence text) { - return Comparing.equal(getText(), text, true); - } - - @Override - public boolean textMatches(@NotNull PsiElement element) { - return getText().equals(element.getText()); - } - - @Override - public void accept(@NotNull PsiElementVisitor visitor) { - visitor.visitElement(this); - } - - @Override - public void acceptChildren(@NotNull PsiElementVisitor visitor) { - PsiElement child = getFirstChild(); - while (child != null) { - child.accept(visitor); - child = child.getNextSibling(); - } - } - - @Override - public boolean isValid() { - final PsiElement parent = getParent(); - return parent != null && parent.isValid(); - } - - @Override - public boolean isWritable() { - final PsiElement parent = getParent(); - return parent != null && parent.isWritable(); - } - - @Override - @NotNull - public PsiReference[] getReferences() { - return SharedPsiElementImplUtil.getReferences(this); - } - - @Override - public PsiElement getContext() { - return getParent(); - } - - @Override - public boolean isPhysical() { - final PsiElement parent = getParent(); - return parent != null && parent.isPhysical(); - } - - @Override - @NotNull - public GlobalSearchScope getResolveScope() { - return ResolveScopeManager.getElementResolveScope(this); - } - - @Override - @NotNull - public SearchScope getUseScope() { - return ResolveScopeManager.getElementUseScope(this); - } - - /** - * Returns the UI presentation data for the PSI element. - * - * @return null, unless overridden in a subclass. - */ - @Override - public ItemPresentation getPresentation() { - return null; - } - - @Override - public String getName() { - return null; - } - - @Override - public void navigate(boolean requestFocus) { - final Navigatable descriptor = PsiNavigationSupport.getInstance().getDescriptor(this); - if (descriptor != null) descriptor.navigate(requestFocus); - } - - @Override - public boolean canNavigate() { - return true; - } - - @Override - public boolean canNavigateToSource() { - final Navigatable descriptor = PsiNavigationSupport.getInstance().getDescriptor(this); - return descriptor != null && descriptor.canNavigateToSource(); - } - - @NotNull - protected T[] findChildrenByClass(Class aClass) { - List result = new ArrayList<>(); - for (PsiElement cur = getFirstChild(); cur != null; cur = cur.getNextSibling()) { - if (aClass.isInstance(cur)) result.add((T)cur); - } - return result.toArray(ArrayUtil.newArray(aClass, result.size())); - } - - @Nullable - protected T findChildByClass(Class aClass) { - for (PsiElement cur = getFirstChild(); cur != null; cur = cur.getNextSibling()) { - if (aClass.isInstance(cur)) return (T)cur; - } - return null; - } - - @NotNull - protected T findNotNullChildByClass(Class aClass) { - return notNullChild(findChildByClass(aClass)); - } - - @NotNull - protected T notNullChild(T child) { - if (child == null) { - LOG.error(getText() + "\n parent=" + getParent().getText()); - } - return child; - } - - @Override - public boolean isEquivalentTo(final PsiElement another) { - return this == another; - } -} diff --git a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java index 5b7c95f66247..67a2d2e54f23 100644 --- a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java +++ b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java @@ -17,6 +17,8 @@ package com.intellij.formatting; import com.intellij.formatting.engine.ExpandableIndent; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.TextRange; import com.intellij.psi.codeStyle.CodeStyleSettings; @@ -38,6 +40,7 @@ import java.util.Set; * The main idea of block wrapping is to associate information about {@link WhiteSpace white space before block} with the block itself. */ public class InitialInfoBuilder { + private static final Logger LOG = Logger.getInstance(InitialInfoBuilder.class); private static final RangesAssert ASSERT = new RangesAssert(); private static final boolean INLINE_TABS_ENABLED = "true".equalsIgnoreCase(System.getProperty("inline.tabs.enabled")); @@ -46,7 +49,7 @@ public class InitialInfoBuilder { private final MultiMap myBlocksToAlign = new MultiMap<>(); private final Set myAlignmentsInsideRangeToModify = ContainerUtil.newHashSet(); - private boolean myCollectAlignmentsInsideFormattingRange = false; + private boolean myCollectAlignmentsInsideFormattingRange; private final FormattingDocumentModel myModel; private final FormatTextRanges myAffectedRanges; @@ -88,14 +91,14 @@ public class InitialInfoBuilder { myFormatterTagHandler = new FormatterTagHandler(settings); } - protected static InitialInfoBuilder prepareToBuildBlocksSequentially( - Block root, - FormattingDocumentModel model, - FormatProcessor.FormatOptions formatOptions, - CodeStyleSettings settings, - CommonCodeStyleSettings.IndentOptions options, - @NotNull FormattingProgressCallback progressCallback) - { + @NotNull + static InitialInfoBuilder prepareToBuildBlocksSequentially( + Block root, + FormattingDocumentModel model, + FormatProcessor.FormatOptions formatOptions, + CodeStyleSettings settings, + CommonCodeStyleSettings.IndentOptions options, + @NotNull FormattingProgressCallback progressCallback) { InitialInfoBuilder builder = new InitialInfoBuilder(root, model, formatOptions.myAffectedRanges, settings, options, formatOptions.myInterestingOffset, progressCallback); builder.setCollectAlignmentsInsideFormattingRange(formatOptions.myReformatContext); builder.buildFrom(root, 0, null, null, null); @@ -273,8 +276,24 @@ public class InitialInfoBuilder { if (!state.readOnly) { try { subBlocks.set(currentBlockIndex, null); // to prevent extra strong refs during model building - } catch (Throwable ex) { - // read-only blocks + } + catch (Throwable ex) { + // todo fix kotlin + if ("org.jetbrains.kotlin.idea.formatter.KotlinBlock".equals(currentRoot.getClass().getName())) { + // ignore + } + else { + // read-only blocks + String msg = "Unable to null elements of list I got from getSubBlocks(): " + subBlocks.getClass() + + ". If you really want to return immutable list, please mark " + currentRoot.getClass() + + " with 'ReadOnlyBlockContainer' interface"; + if (ApplicationManager.getApplication().isInternal() || ApplicationManager.getApplication().isUnitTestMode()) { + LOG.error(msg, ex); + } + else { + LOG.warn(msg, ex); + } + } } } diff --git a/platform/lang-impl/src/com/intellij/formatting/contextConfiguration/ConfigureCodeStyleOnSelectedFragment.java b/platform/lang-impl/src/com/intellij/formatting/contextConfiguration/ConfigureCodeStyleOnSelectedFragment.java index 855007f8d9e2..1a6a67ed54c9 100644 --- a/platform/lang-impl/src/com/intellij/formatting/contextConfiguration/ConfigureCodeStyleOnSelectedFragment.java +++ b/platform/lang-impl/src/com/intellij/formatting/contextConfiguration/ConfigureCodeStyleOnSelectedFragment.java @@ -34,6 +34,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsCodeFragmentFilter; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider; import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.IncorrectOperationException; @@ -177,6 +178,7 @@ public class ConfigureCodeStyleOnSelectedFragment implements IntentionAction, Lo private void applyFromUiToSettings() { try { myTabbedLanguagePanel.apply(mySettings); + CodeStyleSettingsManager.getInstance(myEditor.getProject()).notifyCodeStyleSettingsChanged(); } catch (ConfigurationException e) { LOG.debug("Can not apply code style settings from context menu to project code style settings"); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileItemProvider.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileItemProvider.java index 8eb2deec3c6c..afff5bd296b0 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileItemProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileItemProvider.java @@ -114,7 +114,7 @@ public class GotoFileItemProvider extends DefaultChooseByNameItemProvider { * Invoke contributors directly, as multi-threading isn't of much value in Goto File, * and filling {@link ContributorsBasedGotoByModel#myContributorToItsSymbolsMap} is expensive for the default contributor. */ - private void processNames(Processor nameProcessor) { + private void processNames(Processor nameProcessor) { List contributors = DumbService.getDumbAwareExtensions(myProject, ChooseByNameContributor.FILE_EP_NAME); for (ChooseByNameContributor contributor : contributors) { if (contributor instanceof DefaultFileNavigationContributor) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/newclass/CreateWithTemplatesDialogPanel.java b/platform/lang-impl/src/com/intellij/ide/actions/newclass/CreateWithTemplatesDialogPanel.java index e79d18e6354e..9897166996ce 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/newclass/CreateWithTemplatesDialogPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/newclass/CreateWithTemplatesDialogPanel.java @@ -10,13 +10,15 @@ import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Trinity; import com.intellij.ui.DocumentAdapter; -import com.intellij.ui.JBColor; import com.intellij.ui.ScrollingUtil; import com.intellij.ui.SimpleListCellRenderer; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBPanel; +import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBTextField; +import com.intellij.ui.components.fields.ExtendableTextComponent; +import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.util.BooleanFunction; import com.intellij.util.Consumer; import com.intellij.util.ui.JBUI; @@ -34,7 +36,7 @@ import static com.intellij.ide.ui.laf.darcula.DarculaUIUtil.Outline; public class CreateWithTemplatesDialogPanel extends JBPanel implements Disposable { - private final JBTextField myNameField; + private final ExtendableTextField myNameField; private final JList> myTemplatesList; private JBPopup myErrorPopup; @@ -44,6 +46,7 @@ public class CreateWithTemplatesDialogPanel extends JBPanel implements Disposabl public CreateWithTemplatesDialogPanel(@NotNull List> templates, @Nullable String selectedItem) { super(new BorderLayout()); + setBackground(JBUI.CurrentTheme.NewClassDialog.panelBackground()); myNameField = createNameField(); myTemplatesList = createTemplatesList(templates); @@ -54,7 +57,14 @@ public class CreateWithTemplatesDialogPanel extends JBPanel implements Disposabl selectTemplate(selectedItem); add(myNameField, BorderLayout.NORTH); - add(myTemplatesList, BorderLayout.CENTER); + + JBScrollPane scrollPane = new JBScrollPane(myTemplatesList); + scrollPane.setBorder(JBUI.Borders.empty()); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + Box listHolder = new Box(BoxLayout.Y_AXIS); + listHolder.setBorder(JBUI.Borders.emptyTop(JBUI.CurrentTheme.NewClassDialog.fieldsSeparatorWidth())); + listHolder.add(scrollPane); + add(listHolder, BorderLayout.CENTER); } public JTextField getNameField() { @@ -100,8 +110,8 @@ public class CreateWithTemplatesDialogPanel extends JBPanel implements Disposabl } @NotNull - private JBTextField createNameField() { - JBTextField res = new JBTextField(); + private ExtendableTextField createNameField() { + ExtendableTextField res = new ExtendableTextField(); Dimension minSize = res.getMinimumSize(); Dimension prefSize = res.getPreferredSize(); @@ -111,13 +121,10 @@ public class CreateWithTemplatesDialogPanel extends JBPanel implements Disposabl res.setPreferredSize(prefSize); res.setColumns(30); - JBColor borderColor = JBColor.namedColor( - "TextField.borderColor", - JBColor.namedColor("Component.borderColor", new JBColor(0xbdbdbd, 0x646464)) - ); - Border border = JBUI.Borders.customLine(borderColor, 1, 0, 1, 0); + Border border = JBUI.Borders.customLine(JBUI.CurrentTheme.NewClassDialog.bordersColor(), 1, 0, 1, 0); Border errorBorder = new ErrorBorder(res.getBorder()); res.setBorder(JBUI.Borders.merge(border, errorBorder, false)); + res.setBackground(JBUI.CurrentTheme.NewClassDialog.searchFieldBackground()); res.putClientProperty("StatusVisibleFunction", (BooleanFunction) field -> field.getText().isEmpty()); res.getEmptyText().setText(IdeBundle.message("action.create.new.class.name.field")); @@ -144,38 +151,38 @@ public class CreateWithTemplatesDialogPanel extends JBPanel implements Disposabl private JBList> createTemplatesList(@NotNull List> templates) { JBList> list = new JBList<>(templates); MouseAdapter mouseListener = new MouseAdapter() { - // to avoid selection item under mouse when dialog appears (IDEA-209879) - private boolean isFirstEvent = true; - - @Override - public void mouseMoved(MouseEvent e) { - if (isFirstEvent) { - isFirstEvent = false; - return; - } - selectItem(e.getPoint()); - } - @Override public void mouseClicked(MouseEvent e) { - selectItem(e.getPoint()); - if (myApplyAction != null) myApplyAction.consume(e); - } - - private void selectItem(Point point) { - int index = list.locationToIndex(point); - if (index >= 0) { - list.setSelectedIndex(index); - } + if (myApplyAction != null && e.getClickCount() > 1) myApplyAction.consume(e); } }; - list.addMouseMotionListener(mouseListener); + list.addMouseListener(mouseListener); list.setCellRenderer(LIST_RENDERER); list.setFocusable(false); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + list.addListSelectionListener(e -> { + Trinity selectedValue = list.getSelectedValue(); + if (selectedValue != null) { + setTextFieldIcon(selectedValue.second); + } + }); + + Border border = JBUI.Borders.merge( + JBUI.Borders.emptyLeft(JBUI.scale(5)), + JBUI.Borders.customLine(JBUI.CurrentTheme.NewClassDialog.bordersColor(), 1, 0, 0, 0), + true + ); + list.setBorder(border); return list; } + private void setTextFieldIcon(Icon icon) { + myNameField.setExtensions(new TemplateIconExtension(icon)); + myNameField.repaint(); + } + private void selectTemplate(@Nullable String selectedItem) { if (selectedItem == null) { myTemplatesList.setSelectedIndex(0); @@ -215,6 +222,22 @@ public class CreateWithTemplatesDialogPanel extends JBPanel implements Disposabl } }; + private static class TemplateIconExtension implements ExtendableTextComponent.Extension { + private final Icon icon; + + private TemplateIconExtension(Icon icon) {this.icon = icon;} + + @Override + public Icon getIcon(boolean hovered) { + return icon; + } + + @Override + public boolean isIconBeforeText() { + return true; + } + } + private static class ErrorBorder implements Border { private final Border errorDelegateBorder; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AbstractGotoSEContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AbstractGotoSEContributor.java index 991b90ad6482..2247f2bd88f7 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AbstractGotoSEContributor.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/AbstractGotoSEContributor.java @@ -76,15 +76,16 @@ public abstract class AbstractGotoSEContributor implements SearchEverywh @NotNull Processor consumer) { if (myProject == null) return; //nothing to search if (!isEmptyPatternSupported() && pattern.isEmpty()) return; - if (!isDumbModeSupported() && DumbService.getInstance(myProject).isDumb()) return; - - FilteringGotoByModel model = createModel(myProject); - if (filter != null) { - model.setFilterItems(filter.getSelectedElements()); - } ProgressIndicatorUtils.yieldToPendingWriteActions(); ProgressIndicatorUtils.runInReadActionWithWriteActionPriority(() -> { + if (!isDumbModeSupported() && DumbService.getInstance(myProject).isDumb()) return; + + FilteringGotoByModel model = createModel(myProject); + if (filter != null) { + model.setFilterItems(filter.getSelectedElements()); + } + if (progressIndicator.isCanceled()) return; PsiElement context = psiContext != null && psiContext.isValid() ? psiContext : null; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java index da5a4db7c248..513f68a37618 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java @@ -60,8 +60,6 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModelE } private final ConcurrentMap myContributorToItsSymbolsMap = ContainerUtil.newConcurrentMap(); - private volatile IdFilter myIdFilter; - private volatile boolean myIdFilterForLibraries; @Override public void processNames(final Processor nameProcessor, final boolean checkBoxState) { @@ -125,14 +123,7 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModelE } IdFilter getIdFilter(boolean withLibraries) { - IdFilter idFilter = myIdFilter; - - if (idFilter == null || myIdFilterForLibraries != withLibraries) { - idFilter = IdFilter.getProjectIdFilter(myProject, withLibraries); - myIdFilter = idFilter; - myIdFilterForLibraries = withLibraries; - } - return idFilter; + return IdFilter.getProjectIdFilter(myProject, withLibraries); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/psi/search/FileNameIndexServiceImpl.java b/platform/lang-impl/src/com/intellij/psi/search/FileNameIndexServiceImpl.java index 7e97ea4f7ee1..239831f3b8d2 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/FileNameIndexServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/search/FileNameIndexServiceImpl.java @@ -46,7 +46,7 @@ public class FileNameIndexServiceImpl implements FileNameIndexService { } @Override - public void processAllFileNames(@NotNull Processor processor, @NotNull GlobalSearchScope scope, IdFilter filter) { + public void processAllFileNames(@NotNull Processor processor, @NotNull GlobalSearchScope scope, IdFilter filter) { myIndex.processAllKeys(FilenameIndexImpl.NAME, processor, scope, filter); } diff --git a/platform/lang-impl/src/com/intellij/psi/util/proximity/PsiProximityComparator.java b/platform/lang-impl/src/com/intellij/psi/util/proximity/PsiProximityComparator.java index 213452e4d9c8..6ceccecb0f18 100644 --- a/platform/lang-impl/src/com/intellij/psi/util/proximity/PsiProximityComparator.java +++ b/platform/lang-impl/src/com/intellij/psi/util/proximity/PsiProximityComparator.java @@ -16,7 +16,6 @@ package com.intellij.psi.util.proximity; -import com.intellij.extapi.psi.MetadataPsiElementBase; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.util.Computable; @@ -86,8 +85,6 @@ public class PsiProximityComparator implements Comparator { @Nullable public static WeighingComparable getProximity(final PsiElement element, final PsiElement context) { if (element == null) return null; - //noinspection deprecation,ScheduledForRemoval - if (element instanceof MetadataPsiElementBase) return null; final Module contextModule = context != null ? ModuleUtilCore.findModuleForPsiElement(context) : null; return WeighingService.weigh(WEIGHER_KEY, element, new ProximityLocation(context, contextModule)); } @@ -95,10 +92,7 @@ public class PsiProximityComparator implements Comparator { @Nullable public static WeighingComparable getProximity(final Computable elementComputable, final PsiElement context, ProcessingContext processingContext) { PsiElement element = elementComputable.compute(); - if (element == null) return null; - //noinspection deprecation,ScheduledForRemoval - if (element instanceof MetadataPsiElementBase) return null; - if (context == null) return null; + if (element == null || context == null) return null; Module contextModule = processingContext.get(MODULE_BY_LOCATION); if (contextModule == null) { contextModule = ModuleUtilCore.findModuleForPsiElement(context); diff --git a/platform/lang-impl/testSources/com/intellij/build/output/BuildOutputInstantReaderImplTest.kt b/platform/lang-impl/testSources/com/intellij/build/output/BuildOutputInstantReaderImplTest.kt index 554c7ad6204e..13de477afd31 100644 --- a/platform/lang-impl/testSources/com/intellij/build/output/BuildOutputInstantReaderImplTest.kt +++ b/platform/lang-impl/testSources/com/intellij/build/output/BuildOutputInstantReaderImplTest.kt @@ -104,7 +104,7 @@ ${trashOut.prependIndent(" ")} buf.append(nextLine).append('\n') nextLine = reader.readLine() } - messageConsumer.accept(MessageEventImpl(reader.buildId, kind, null, buf.toString().dropLast(1), null)) + messageConsumer.accept(MessageEventImpl(reader.parentEventId, kind, null, buf.toString().dropLast(1), null)) return@BuildOutputParser true } return@BuildOutputParser false diff --git a/platform/platform-api/src/com/intellij/execution/process/AnsiCommands.java b/platform/platform-api/src/com/intellij/execution/process/AnsiCommands.java new file mode 100644 index 000000000000..d31b7c6b0de6 --- /dev/null +++ b/platform/platform-api/src/com/intellij/execution/process/AnsiCommands.java @@ -0,0 +1,87 @@ +// 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. +package com.intellij.execution.process; + +public final class AnsiCommands { + public static final int SGR_COMMAND_RESET = 0; + public static final int SGR_COMMAND_BOLD = 1; + public static final int SGR_COMMAND_FAINT = 2; + public static final int SGR_COMMAND_ITALIC = 3; + public static final int SGR_COMMAND_UNDERLINE = 4; + public static final int SGR_COMMAND_BLINK_SLOW = 5; + public static final int SGR_COMMAND_BLINK_RAPID = 6; + public static final int SGR_COMMAND_INVERSE = 7; + public static final int SGR_COMMAND_CONCEAL = 8; + public static final int SGR_COMMAND_CROSS_OUT = 9; + public static final int SGR_COMMAND_PRIMARY_FONT = 10; + public static final int SGR_COMMAND_FONT1 = 11; + public static final int SGR_COMMAND_FONT2 = 12; + public static final int SGR_COMMAND_FONT3 = 13; + public static final int SGR_COMMAND_FONT4 = 14; + public static final int SGR_COMMAND_FONT5 = 15; + public static final int SGR_COMMAND_FONT6 = 16; + public static final int SGR_COMMAND_FONT7 = 17; + public static final int SGR_COMMAND_FONT8 = 18; + public static final int SGR_COMMAND_FONT9 = 19; + public static final int SGR_COMMAND_FRAKTUR = 20; + public static final int SGR_COMMAND_DOUBLE_UNDERLINE = 21; + public static final int SGR_COMMAND_NO_BOLD_FAINT = 22; + public static final int SGR_COMMAND_NO_ITALIC_FRAKTUR = 23; + public static final int SGR_COMMAND_NO_UNDERLINE = 24; + public static final int SGR_COMMAND_NO_BLINK = 25; + public static final int SGR_COMMAND_NO_INVERSE = 27; + public static final int SGR_COMMAND_REVEAL = 28; + public static final int SGR_COMMAND_NO_CROSS_OUT = 29; + public static final int SGR_COMMAND_FG_COLOR0 = 30; + public static final int SGR_COMMAND_FG_COLOR1 = 31; + public static final int SGR_COMMAND_FG_COLOR2 = 32; + public static final int SGR_COMMAND_FG_COLOR3 = 33; + public static final int SGR_COMMAND_FG_COLOR4 = 34; + public static final int SGR_COMMAND_FG_COLOR5 = 35; + public static final int SGR_COMMAND_FG_COLOR6 = 36; + public static final int SGR_COMMAND_FG_COLOR7 = 37; + public static final int SGR_COMMAND_FG_COLOR_ENCODED = 38; + public static final int SGR_COMMAND_FG_COLOR_DEFAULT = 39; + public static final int SGR_COMMAND_BG_COLOR0 = 40; + public static final int SGR_COMMAND_BG_COLOR1 = 41; + public static final int SGR_COMMAND_BG_COLOR2 = 42; + public static final int SGR_COMMAND_BG_COLOR3 = 43; + public static final int SGR_COMMAND_BG_COLOR4 = 44; + public static final int SGR_COMMAND_BG_COLOR5 = 45; + public static final int SGR_COMMAND_BG_COLOR6 = 46; + public static final int SGR_COMMAND_BG_COLOR7 = 47; + public static final int SGR_COMMAND_BG_COLOR_ENCODED = 48; + public static final int SGR_COMMAND_BG_COLOR_DEFAULT = 49; + public static final int SGR_COMMAND_FRAMED = 51; + public static final int SGR_COMMAND_ENCIRCLED = 52; + public static final int SGR_COMMAND_OVERLINED = 53; + public static final int SGR_COMMAND_NO_FRAMED_ENCIRCLED = 54; + public static final int SGR_COMMAND_NO_OVERLINED = 55; + public static final int SGR_COMMAND_IDEOGRAM_UNDER_RIGHT = 60; + public static final int SGR_COMMAND_IDEOGRAM_UNDER_RIGHT_DOUBLE = 61; + public static final int SGR_COMMAND_IDEOGRAM_OVER_LEFT = 62; + public static final int SGR_COMMAND_IDEOGRAM_OVER_LEFT_DOUBLE = 63; + public static final int SGR_COMMAND_IDEOGRAM_STRESS = 64; + public static final int SGR_COMMAND_IDEOGRAM_OFF = 65; + public static final int SGR_COMMAND_FG_COLOR8 = 90; + public static final int SGR_COMMAND_FG_COLOR9 = 91; + public static final int SGR_COMMAND_FG_COLOR10 = 92; + public static final int SGR_COMMAND_FG_COLOR11 = 93; + public static final int SGR_COMMAND_FG_COLOR12 = 94; + public static final int SGR_COMMAND_FG_COLOR13 = 95; + public static final int SGR_COMMAND_FG_COLOR14 = 96; + public static final int SGR_COMMAND_FG_COLOR15 = 97; + public static final int SGR_COMMAND_BG_COLOR8 = 100; + public static final int SGR_COMMAND_BG_COLOR9 = 101; + public static final int SGR_COMMAND_BG_COLOR10 = 102; + public static final int SGR_COMMAND_BG_COLOR11 = 103; + public static final int SGR_COMMAND_BG_COLOR12 = 104; + public static final int SGR_COMMAND_BG_COLOR13 = 105; + public static final int SGR_COMMAND_BG_COLOR14 = 106; + public static final int SGR_COMMAND_BG_COLOR15 = 107; + // these are used with SGR_COMMAND_BG_COLOR_ENCODED/SGR_COMMAND_FG_COLOR_ENCODED + public static final int SGR_COLOR_ENCODING_INDEXED = 5; + public static final int SGR_COLOR_ENCODING_RGB = 2; + + private AnsiCommands() { + } +} diff --git a/platform/platform-api/src/com/intellij/execution/process/AnsiEscapeDecoder.java b/platform/platform-api/src/com/intellij/execution/process/AnsiEscapeDecoder.java index adf5f955d5d2..58e058254ade 100644 --- a/platform/platform-api/src/com/intellij/execution/process/AnsiEscapeDecoder.java +++ b/platform/platform-api/src/com/intellij/execution/process/AnsiEscapeDecoder.java @@ -15,31 +15,28 @@ */ package com.intellij.execution.process; +import com.intellij.execution.process.AnsiStreamingLexer.AnsiElementType; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import static com.intellij.execution.process.AnsiStreamingLexer.SGR; +import static com.intellij.execution.process.AnsiStreamingLexer.TEXT; + /** * See ANSI escape code. - * - * @author traff */ public class AnsiEscapeDecoder { - private static final char ESC_CHAR = '\u001B'; // Escape sequence start character - private static final String CSI = ESC_CHAR + "["; // "Control Sequence Initiator" - private static final String M_CSI = "m" + CSI; - private final ColoredOutputTypeRegistry myColoredOutputTypeRegistry = ColoredOutputTypeRegistry.getInstance(); - private String myUnhandledStdout; - private String myUnhandledStderr; - private ProcessOutputType myCurrentStdoutOutputType; - private ProcessOutputType myCurrentStderrOutputType; + + private final AnsiStreamingLexer myStdoutLexer = new AnsiStreamingLexer(); + private final AnsiStreamingLexer myStderrLexer = new AnsiStreamingLexer(); + private final AnsiTerminalEmulator myStdoutEmulator = new AnsiTerminalEmulator(); + private final AnsiTerminalEmulator myStderrEmulator = new AnsiTerminalEmulator(); /** * Parses ansi-color codes from text and sends text fragments with color attributes to textAcceptor @@ -50,185 +47,54 @@ public class AnsiEscapeDecoder { * It can implement ColoredChunksAcceptor to receive list of pairs (text, attribute). */ public void escapeText(@NotNull String text, @NotNull Key outputType, @NotNull ColoredTextAcceptor textAcceptor) { - text = prependUnhandledText(text, outputType); - int pos = 0; - int findEscSeqFromIndex = 0; + AnsiStreamingLexer effectiveLexer; + AnsiTerminalEmulator effectiveEmulator; + if (ProcessOutputType.isStdout(outputType)) { + effectiveLexer = myStdoutLexer; + effectiveEmulator = myStdoutEmulator; + } + else if (ProcessOutputType.isStderr(outputType)) { + effectiveLexer = myStderrLexer; + effectiveEmulator = myStderrEmulator; + } + else { + processTextWithoutAnsi(text, outputType, textAcceptor); + return; + } + + effectiveLexer.append(text); + effectiveLexer.advance(); + List> chunks = null; - int unhandledSuffixLength = 0; - while (true) { - int escSeqBeginInd = findEscSeqBeginIndex(text, findEscSeqFromIndex); - if (escSeqBeginInd < 0) { - if (escSeqBeginInd < -1) { - unhandledSuffixLength = decodeUnhandledSuffixLength(escSeqBeginInd); - } - break; + AnsiElementType elementType; + while ((elementType = effectiveLexer.getElementType()) != null) { + String elementText = effectiveLexer.getElementTextSmart(); + assert elementText != null; + if (elementType == SGR) { + effectiveEmulator.processSgr(elementText); } - int escSeqEndInd = findConsecutiveEscSequencesEndIndex(text, escSeqBeginInd); - if (escSeqEndInd < 0) { - if (escSeqEndInd == -1) { - // malformed escape sequence => add ESC[ - findEscSeqFromIndex = escSeqBeginInd + CSI.length(); - } - else { - unhandledSuffixLength = decodeUnhandledSuffixLength(escSeqEndInd); - break; - } + else if (elementType == TEXT) { + chunks = processTextChunk(chunks, elementText, outputType, textAcceptor); } else { - assert escSeqBeginInd <= escSeqEndInd; - if (pos < escSeqBeginInd) { - chunks = processTextChunk(chunks, text.substring(pos, escSeqBeginInd), outputType, textAcceptor); - } - pos = escSeqEndInd + 1; - findEscSeqFromIndex = pos; - if (text.charAt(escSeqEndInd) == 'm') { - String escSeq = text.substring(escSeqBeginInd, escSeqEndInd + 1); - // this is a simple fix for RUBY-8996: - // we replace several consecutive escape sequences with one which contains all these sequences - String colorAttribute = StringUtil.replace(escSeq, M_CSI, ";"); - ProcessOutputType resultType = myColoredOutputTypeRegistry.getOutputType(colorAttribute, outputType); - if (resultType.isStdout()) { - myCurrentStdoutOutputType = resultType; - } - else if (resultType.isStderr()) { - myCurrentStderrOutputType = resultType; - } - } + assert elementType == AnsiStreamingLexer.CONTROL; + // Commands other than SGR are unhandled currently. Extend here when it's needed. } + effectiveLexer.advance(); } - if (pos < text.length() - unhandledSuffixLength) { - chunks = processTextChunk(chunks, text.substring(pos, text.length() - unhandledSuffixLength), outputType, textAcceptor); - } - updateUnhandledSuffix(text, outputType, unhandledSuffixLength); if (chunks != null && textAcceptor instanceof ColoredChunksAcceptor) { ((ColoredChunksAcceptor)textAcceptor).coloredChunksAvailable(chunks); } } - private void updateUnhandledSuffix(@NotNull String text, @NotNull Key outputType, int unhandledSuffixLength) { - String unhandledSuffix = unhandledSuffixLength > 0 ? text.substring(text.length() - unhandledSuffixLength) : null; - if (ProcessOutputType.isStdout(outputType)) { - myUnhandledStdout = unhandledSuffix; - } - else if (ProcessOutputType.isStderr(outputType)) { - myUnhandledStderr = unhandledSuffix; - } - } - - @NotNull - private String prependUnhandledText(@NotNull String text, @NotNull Key outputType) { - String prevUnhandledText = null; - if (ProcessOutputType.isStdout(outputType)) { - prevUnhandledText = myUnhandledStdout; - myUnhandledStdout = null; - } - else if (ProcessOutputType.isStderr(outputType)) { - prevUnhandledText = myUnhandledStderr; - myUnhandledStderr = null; - } - return prevUnhandledText != null ? prevUnhandledText + text : text; - } - /** - * Returns the index of the first occurrence of CSI within the passed string that is greater than or equal to {@code fromIndex}, - * or negative number if CSI is not found: -1 - (length of text suffix to keep in case of an incomplete CSI). + * Fallback method for the {@link ProcessOutputTypes#SYSTEM system} output type. ANSI is not supported */ - private static int findEscSeqBeginIndex(@NotNull String text, int fromIndex) { - int ind = text.indexOf(CSI.charAt(0), fromIndex); - if (ind == -1) { - return -1; + private void processTextWithoutAnsi(@NotNull String text, @NotNull Key outputType, @NotNull ColoredTextAcceptor textAcceptor) { + List> chunks = processTextChunk(null, text, outputType, textAcceptor); + if (chunks != null && textAcceptor instanceof ColoredChunksAcceptor) { + ((ColoredChunksAcceptor)textAcceptor).coloredChunksAvailable(chunks); } - if (ind == text.length() - 1) { - return encodeUnhandledSuffixLength(text, ind); - } - return text.charAt(ind + 1) == CSI.charAt(1) ? ind : -1; - } - - /** - * Returns end index of all consecutive escape sequences started at {@code firstEscSeqBeginInd}, or - * a negative number if not found. Since an escape sequence could be split among several subsequent output chunks - * (e.g. because of automatic flushing of standard stream when its buffer is full), it should be parsed - * when all the needed output chunks are available. To achieve that, the return value encodes - * the length of the passed string suffix to keep in case of an incomplete last escape sequence: - * {@code -1 - (length of string suffix to keep in case of an incomplete last escape sequence)}.

- * If the return value is -1, no string suffix should be kept => a malformed escape sequence has been encountered. - * If the return value is less than -1, no actual handing of the incomplete escape sequence should be performed, - * the string suffix length should be decoded with {@code #decodeUnhandledSuffixLength(the return value)} and the suffix - * should be preserved until the next output chunk is available. - */ - private static int findConsecutiveEscSequencesEndIndex(@NotNull String text, int firstEscSeqBeginInd) { - int escSeqBeginInd = firstEscSeqBeginInd; - int lastMatchedColorEscSeqEndInd = -1; - int escSeqEndInd; - while ((escSeqEndInd = findEscSeqEndIndex(text, escSeqBeginInd)) >= 0) { - if (text.charAt(escSeqEndInd) != 'm') { - // Handle non-color escape sequences separately - // ColoredOutputTypeRegistry expects only color escape sequences and in a single consecutive text chunk - return lastMatchedColorEscSeqEndInd > 0 ? lastMatchedColorEscSeqEndInd : escSeqEndInd; - } - escSeqBeginInd = escSeqEndInd + 1; - lastMatchedColorEscSeqEndInd = escSeqEndInd; - if (escSeqEndInd + 1 >= text.length()) { - return encodeUnhandledSuffixLength(text, firstEscSeqBeginInd); - } - if (text.charAt(escSeqEndInd + 1) != CSI.charAt(0)) { - break; - } - if (escSeqEndInd + 2 >= text.length()) { - return encodeUnhandledSuffixLength(text, firstEscSeqBeginInd); - } - if (text.charAt(escSeqEndInd + 2) != CSI.charAt(1)) { - break; - } - } - if (escSeqEndInd < -1) { - return encodeUnhandledSuffixLength(text, firstEscSeqBeginInd); - } - return lastMatchedColorEscSeqEndInd; - } - - /** - * @implSpec {@code The ESC [ is followed by any number (including none) of "parameter bytes" in the - * range 0x30-0x3F (ASCII 0-9:;<=>?), then by any number of "intermediate bytes" in the range 0x20-0x2F (ASCII space and - * !"#$%&'()*+,-./), then finally by a single "final byte" in the range 0x40-0x7E (ASCII @A-Z[\]^_`a-z{|}~).} - * @implNote Also, there are different sequences, aside CSI - */ - private static int findEscSeqEndIndex(@NotNull String text, int escSeqBeginInd) { - int parameterEndInd = escSeqBeginInd + CSI.length(); - while (parameterEndInd < text.length()) { - char ch = text.charAt(parameterEndInd); - if (0x30 <= ch && ch <= 0x3F) { - parameterEndInd++; - } - else { - break; - } - } - while (parameterEndInd < text.length()) { - char ch = text.charAt(parameterEndInd); - if (0x20 <= ch && ch <= 0x2F) { - parameterEndInd++; - } - else { - break; - } - } - if (parameterEndInd == text.length()) { - return encodeUnhandledSuffixLength(text, escSeqBeginInd); - } - char lastChar = text.charAt(parameterEndInd); - return 0x40 <= lastChar && lastChar <= 0x7E ? parameterEndInd : -1; - } - - private static int encodeUnhandledSuffixLength(@NotNull String text, int suffixStartInd) { - return -1 - (text.length() - suffixStartInd); - } - - private static int decodeUnhandledSuffixLength(int encodedUnhandledSuffixLength) { - if (encodedUnhandledSuffixLength >= -1) { - throw new AssertionError(); - } - return -encodedUnhandledSuffixLength - 1; } @Nullable @@ -252,10 +118,10 @@ public class AnsiEscapeDecoder { @NotNull protected Key getCurrentOutputAttributes(@NotNull Key outputType) { if (ProcessOutputType.isStdout(outputType)) { - return ObjectUtils.notNull(myCurrentStdoutOutputType, outputType); + return myStdoutEmulator.isInitialState() ? outputType : myColoredOutputTypeRegistry.getOutputType(myStdoutEmulator, outputType); } if (ProcessOutputType.isStderr(outputType)) { - return ObjectUtils.notNull(myCurrentStderrOutputType, outputType); + return myStderrEmulator.isInitialState() ? outputType : myColoredOutputTypeRegistry.getOutputType(myStderrEmulator, outputType); } return outputType; } diff --git a/platform/platform-api/src/com/intellij/execution/process/AnsiStreamingLexer.java b/platform/platform-api/src/com/intellij/execution/process/AnsiStreamingLexer.java new file mode 100644 index 000000000000..b78f435e6920 --- /dev/null +++ b/platform/platform-api/src/com/intellij/execution/process/AnsiStreamingLexer.java @@ -0,0 +1,162 @@ +// 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. +package com.intellij.execution.process; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class AnsiStreamingLexer { + // element types + static final AnsiElementType TEXT = new AnsiElementType("TEXT"); + static final AnsiElementType SGR = new AnsiElementType("SGR"); + static final AnsiElementType CONTROL = new AnsiElementType("CONTROL"); + + static final char ESCAPE = '\u001b'; + static final String CSI = ESCAPE + "["; + static final char SGR_SUFFIX = 'm'; + + // current text buffer + private String myBuffer = ""; + + // current token start offset + private int myStartOffset = 0; + + // current token end offset + private int myEndOffset = 0; + + private AnsiElementType myElementType = null; + + /** + * Appending a {@code text} to the stream + */ + void append(@NotNull String text) { + myBuffer = myEndOffset < myBuffer.length() ? myBuffer.substring(myEndOffset) + text : text; + myStartOffset = 0; + myEndOffset = 0; + } + + /** + * @return element type of current token. null means we are not started or at the end of stream + */ + @Nullable + AnsiElementType getElementType() { + return myElementType; + } + + /** + * @return text of current token of null if we've not started or at the end of stream + */ + @Nullable + String getElementText() { + return myElementType == null ? null : myBuffer.substring(myStartOffset, myEndOffset); + } + + /** + * @return for {@link #SGR} elements return only content part of the text, between {@code CSI} and {@code m}. For the rest works + * the same way as {@link #getElementText()} + */ + @Nullable + String getElementTextSmart() { + if (myElementType == SGR) { + return myBuffer.substring(myStartOffset + CSI.length(), myEndOffset - 1); + } + return getElementText(); + } + + /** + * advances lexer to the next token if possible + */ + void advance() { + if (myEndOffset == myBuffer.length()) { + // EOF + myElementType = null; + return; + } + myStartOffset = myEndOffset; + if (myBuffer.charAt(myEndOffset) != ESCAPE) { + // just a text + advanceToEscape(); + return; + } + if (myEndOffset + 1 == myBuffer.length()) { + incompleteSequence(); + return; + } + + myEndOffset++; + if (myBuffer.charAt(myEndOffset) == '[') { + myEndOffset++; + processCSISequence(); + return; + } + // There can by anything from 0x40–0x5F https://en.wikipedia.org/wiki/ANSI_escape_code#Escape_sequences + // but we are ignoring this for now + advanceToEscape(); + } + + /** + * Advancing after CSI sequence, see https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences + * + * @implSpec {@code The ESC [ is followed by any number (including none) of "parameter bytes" in the + * range 0x30–0x3F (ASCII 0–9:;<=>?), then by any number of "intermediate bytes" in the range 0x20–0x2F (ASCII space and + * !"#$%&'()*+,-./), then finally by a single "final byte" in the range 0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~).} + */ + private void processCSISequence() { + while (myEndOffset < myBuffer.length() && isInRange(myBuffer.charAt(myEndOffset), (char)0x30, (char)0x3F)) { + myEndOffset++; + } + while (myEndOffset < myBuffer.length() && isInRange(myBuffer.charAt(myEndOffset), (char)0x20, (char)0x2F)) { + myEndOffset++; + } + if (myEndOffset == myBuffer.length()) { + incompleteSequence(); + return; + } + + char lastChar = myBuffer.charAt(myEndOffset); + myEndOffset++; + if (lastChar == SGR_SUFFIX) { + myElementType = SGR; + } + else if (0x40 <= lastChar && lastChar <= 0x7E) { + myElementType = CONTROL; + } + else { + // broken seqeuence, considering as a text + advanceToEscape(); + } + } + + private void advanceToEscape() { + int escapeIndex = myBuffer.indexOf(ESCAPE, myEndOffset); + myEndOffset = escapeIndex != -1 ? escapeIndex : myBuffer.length(); + myElementType = TEXT; + } + + private void incompleteSequence() { + myElementType = null; + myEndOffset = myStartOffset; + } + + /** + * @return true iff {@code character} is inside chars range inclusive + */ + private static boolean isInRange(char character, char startRange, char endRange) { + return startRange <= character && character <= endRange; + } + + /** + * representing element type for ANSI stream. Not using ElementType to avoid wasting tokens + */ + static final class AnsiElementType { + private final String myName; + + private AnsiElementType(String name) { + myName = name; + } + + @Override + public String toString() { + return "ANSI: " + myName; + } + } +} diff --git a/platform/platform-api/src/com/intellij/execution/process/AnsiTerminalColor.java b/platform/platform-api/src/com/intellij/execution/process/AnsiTerminalColor.java new file mode 100644 index 000000000000..5ede1f42465f --- /dev/null +++ b/platform/platform-api/src/com/intellij/execution/process/AnsiTerminalColor.java @@ -0,0 +1,31 @@ +// 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. +package com.intellij.execution.process; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; + +/** + * Interface to work with ANSI-defined terminal colors + */ +interface AnsiTerminalColor { + /** + * @return command part for serializing this color. + * @implSpec this method MUST NOT return an escape sequence. Only the part that should be wrapped to {@link #SGR_COMMAND_FG_COLOR_ENCODED} or + * {@link #SGR_COMMAND_BG_COLOR_ENCODED}. E.g. {@code 2;255;255;255 } + */ + @NotNull + String getAnsiEncodedColor(); + + /** + * @return a {@link java.awt.Color color} representing this one or null if this is a pre-set configurable color 0-15 + */ + @Nullable + Color getColor(); + + /** + * @return a color index for this terminal color if available. Returns {@code -1} for pure RGB encoded color + */ + int getColorIndex(); +} diff --git a/platform/platform-api/src/com/intellij/execution/process/AnsiTerminalEmulator.java b/platform/platform-api/src/com/intellij/execution/process/AnsiTerminalEmulator.java new file mode 100644 index 000000000000..fd1fc7c77b5c --- /dev/null +++ b/platform/platform-api/src/com/intellij/execution/process/AnsiTerminalEmulator.java @@ -0,0 +1,702 @@ +// 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. +package com.intellij.execution.process; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.markup.EffectType; +import com.intellij.openapi.util.ClearableLazyValue; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.function.IntConsumer; + +import static com.intellij.execution.process.AnsiCommands.*; +import static com.intellij.execution.process.AnsiStreamingLexer.SGR_SUFFIX; +import static com.intellij.execution.process.AnsiTerminalEmulator.BlinkSpeed.RAPID_BLINK; +import static com.intellij.execution.process.AnsiTerminalEmulator.BlinkSpeed.SLOW_BLINK; +import static com.intellij.execution.process.AnsiTerminalEmulator.Boldness.BOLD; +import static com.intellij.execution.process.AnsiTerminalEmulator.Boldness.FAINT; +import static com.intellij.execution.process.AnsiTerminalEmulator.FrameType.*; +import static com.intellij.execution.process.AnsiTerminalEmulator.Underline.DOUBLE_UNDERLINE; +import static com.intellij.execution.process.AnsiTerminalEmulator.Underline.SINGLE_UNDERLINE; +import static com.intellij.openapi.editor.markup.EffectType.BOLD_LINE_UNDERSCORE; +import static com.intellij.openapi.editor.markup.EffectType.LINE_UNDERSCORE; + +/** + * Emulates the ANSI terminal state + */ +class AnsiTerminalEmulator { + private static final Logger LOG = Logger.getInstance(AnsiTerminalEmulator.class); + + private static final AnsiTerminalEmulator EMPTY_EMULATOR = new AnsiTerminalEmulator(); + private static final int MAX_8BIT_COLOR_INDEX = 15; + private static final int COLOR_CUBE_MIN_INDEX = MAX_8BIT_COLOR_INDEX + 1; + private static final int GRAY_MIN_INDEX = 232; + + @NotNull + private Font myFont = Font.DEFAULT; + @NotNull + private Boldness myBoldness = Boldness.DEFAULT; + @NotNull + private Underline myUnderline = Underline.DEFAULT; + @NotNull + private BlinkSpeed myBlink = BlinkSpeed.DEFAULT; + @NotNull + private FrameType myFrameType = FrameType.DEFAULT; + + private boolean myIsItalic; + private boolean myIsInverse; + private boolean myIsConseal; + private boolean myIsCrossedOut; + private boolean myIsFraktur; + private boolean myIsOverlined; + + private AnsiTerminalColor myBackgroundColor; + private AnsiTerminalColor myForegroundColor; + + private final ClearableLazyValue mySerializedSgrStateProvider = ClearableLazyValue.create( + () -> computeAnsiSerializedSGRState()); + + /** + * Consumes SGR - Select Graphic Rendition control sequence and changes emulator's state accordingly + */ + public void processSgr(@NotNull String sgrSequenceBody) { + /* + The ITU's T.416 Information technology - Open Document Architecture (ODA) and interchange format: + https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.416-199303-I!!PDF-E&type=items + uses ':' as separator characters instead * + */ + List sgrSequenceParts = StringUtil.split(sgrSequenceBody, StringUtil.containsChar(sgrSequenceBody, ':') ? ":" : ";"); + Iterator sgrCodesIterator = ContainerUtil.map(sgrSequenceParts, it -> { + try { + return it.isEmpty() ? 0 : Integer.parseInt(it); + } + catch (NumberFormatException e) { + LOG.warn("Could not parse integer: " + it + " in " + sgrSequenceBody); + return null; + } + }).iterator(); + + while (sgrCodesIterator.hasNext()) { + Integer command = sgrCodesIterator.next(); + if (command == null) { + break; + } + processSgr(command, sgrCodesIterator); + } + } + + /** + * Changes terminal state according to {@code commandCode} + * @param sgrCodesIterator iterator of subsequent codes if any. May be necessary for multi-param sgr sequences, like setting color + */ + private void processSgr(int commandCode, Iterator sgrCodesIterator) { + switch (commandCode) { + case SGR_COMMAND_RESET: + resetTerminal(); + break; + case SGR_COMMAND_BOLD: + myBoldness = BOLD; + break; + case SGR_COMMAND_FAINT: + myBoldness = FAINT; + break; + case SGR_COMMAND_ITALIC: + myIsItalic = true; + break; + case SGR_COMMAND_UNDERLINE: + myUnderline = SINGLE_UNDERLINE; + break; + case SGR_COMMAND_BLINK_SLOW: + myBlink = SLOW_BLINK; + break; + case SGR_COMMAND_BLINK_RAPID: + myBlink = RAPID_BLINK; + break; + case SGR_COMMAND_INVERSE: + myIsInverse = true; + break; + case SGR_COMMAND_CONCEAL: + myIsConseal = true; + break; + case SGR_COMMAND_CROSS_OUT: + myIsCrossedOut = true; + break; + case SGR_COMMAND_PRIMARY_FONT: + myFont = Font.DEFAULT; + break; + case SGR_COMMAND_FRAKTUR: + myIsFraktur = true; + break; + case SGR_COMMAND_DOUBLE_UNDERLINE: + myBoldness = Boldness.DEFAULT; + // this is ECMA-48 behaviour. Probably we could make this configurable via flag? + myUnderline = DOUBLE_UNDERLINE; + break; + case SGR_COMMAND_NO_BOLD_FAINT: + myBoldness = Boldness.DEFAULT; + break; + case SGR_COMMAND_NO_ITALIC_FRAKTUR: + myIsFraktur = false; + myIsItalic = false; + break; + case SGR_COMMAND_NO_UNDERLINE: + myUnderline = Underline.DEFAULT; + break; + case SGR_COMMAND_NO_BLINK: + myBlink = BlinkSpeed.DEFAULT; + break; + case SGR_COMMAND_NO_INVERSE: + myIsInverse = false; + break; + case SGR_COMMAND_REVEAL: + myIsConseal = false; + break; + case SGR_COMMAND_NO_CROSS_OUT: + myIsCrossedOut = false; + break; + case SGR_COMMAND_FG_COLOR_ENCODED: + myForegroundColor = decodeColor(sgrCodesIterator); + break; + case SGR_COMMAND_FG_COLOR_DEFAULT: + myForegroundColor = null; + break; + case SGR_COMMAND_BG_COLOR_ENCODED: + myBackgroundColor = decodeColor(sgrCodesIterator); + break; + case SGR_COMMAND_BG_COLOR_DEFAULT: + myBackgroundColor = null; + break; + case SGR_COMMAND_FRAMED: + myFrameType = FRAMED; + break; + case SGR_COMMAND_ENCIRCLED: + myFrameType = ENCIRCLED; + break; + case SGR_COMMAND_OVERLINED: + myIsOverlined = true; + break; + case SGR_COMMAND_NO_FRAMED_ENCIRCLED: + myFrameType = NO_FRAME; + break; + case SGR_COMMAND_NO_OVERLINED: + myIsOverlined = false; + break; + default: + if (commandCode >= SGR_COMMAND_FONT1 && commandCode <= SGR_COMMAND_FONT9) { + myFont = Font.values()[commandCode - 10]; + } + else if (commandCode >= SGR_COMMAND_FG_COLOR0 && commandCode <= SGR_COMMAND_FG_COLOR7) { + myForegroundColor = new EightBitColor(commandCode - SGR_COMMAND_FG_COLOR0); + } + else if (commandCode >= SGR_COMMAND_BG_COLOR0 && commandCode <= SGR_COMMAND_BG_COLOR7) { + myBackgroundColor = new EightBitColor(commandCode - SGR_COMMAND_BG_COLOR0); + } + else if (commandCode >= SGR_COMMAND_IDEOGRAM_UNDER_RIGHT && commandCode <= SGR_COMMAND_IDEOGRAM_OFF) { + LOG.debug("Ignore no-op ideogram sequence: " + commandCode); + } + else if (commandCode >= SGR_COMMAND_FG_COLOR8 && commandCode <= SGR_COMMAND_FG_COLOR15) { + myForegroundColor = new EightBitColor(commandCode - SGR_COMMAND_FG_COLOR8 + 8); + } + else if (commandCode >= SGR_COMMAND_BG_COLOR8 && commandCode <= SGR_COMMAND_BG_COLOR15) { + myBackgroundColor = new EightBitColor(commandCode - SGR_COMMAND_BG_COLOR8 + 8); + } + else { + LOG.warn("Unknown command " + commandCode); + return; + } + } + mySerializedSgrStateProvider.drop(); + } + + /** + * @return an ANSI string representing the SGR state of the current emulator. Same state is always represented with the same string. + */ + @NotNull + public String getAnsiSerializedSGRState() { + return Objects.requireNonNull(mySerializedSgrStateProvider.getValue()); + } + + /** + * @return an ANSI string representing the SGR state of the current emulator. Same state is always represented with the same string. + */ + @NotNull + public String computeAnsiSerializedSGRState() { + List state = new ArrayList<>(); + IntConsumer codeConsumer = it -> state.add(Integer.toString(it)); + + codeConsumer.accept(SGR_COMMAND_RESET); + if (myFont != Font.DEFAULT) { + codeConsumer.accept(myFont.sgrCode); + } + if (myBoldness != Boldness.DEFAULT) { + codeConsumer.accept(myBoldness.sgrCode); + } + if (myUnderline != Underline.DEFAULT) { + codeConsumer.accept(myUnderline.sgrCode); + } + if (myFont != Font.DEFAULT) { + codeConsumer.accept(myFont.sgrCode); + } + if (myBlink != BlinkSpeed.DEFAULT) { + codeConsumer.accept(myBlink.sgrCode); + } + if (myIsInverse) { + codeConsumer.accept(SGR_COMMAND_INVERSE); + } + if (myBackgroundColor != null) { + codeConsumer.accept(SGR_COMMAND_BG_COLOR_ENCODED); + state.add(myBackgroundColor.getAnsiEncodedColor()); + } + if (myForegroundColor != null) { + codeConsumer.accept(SGR_COMMAND_FG_COLOR_ENCODED); + state.add(myForegroundColor.getAnsiEncodedColor()); + } + if (myIsItalic) { + codeConsumer.accept(SGR_COMMAND_ITALIC); + } + if (myIsConseal) { + codeConsumer.accept(SGR_COMMAND_CONCEAL); + } + if (myIsCrossedOut) { + codeConsumer.accept(SGR_COMMAND_CROSS_OUT); + } + if (myIsFraktur) { + codeConsumer.accept(SGR_COMMAND_FRAKTUR); + } + if (myFrameType != FrameType.DEFAULT) { + codeConsumer.accept(myFrameType.sgrCode); + } + if (myIsOverlined) { + codeConsumer.accept(SGR_COMMAND_OVERLINED); + } + return AnsiStreamingLexer.CSI + StringUtil.join(state, ";") + SGR_SUFFIX; + } + + /** + * Reset terminal values to defaults + */ + private void resetTerminal() { + myFont = EMPTY_EMULATOR.myFont; + myBoldness = EMPTY_EMULATOR.myBoldness; + myUnderline = EMPTY_EMULATOR.myUnderline; + myBackgroundColor = EMPTY_EMULATOR.myBackgroundColor; + myForegroundColor = EMPTY_EMULATOR.myForegroundColor; + myFrameType = EMPTY_EMULATOR.myFrameType; + myBlink = EMPTY_EMULATOR.myBlink; + myIsInverse = EMPTY_EMULATOR.myIsInverse; + myIsItalic = EMPTY_EMULATOR.myIsItalic; + myIsConseal = EMPTY_EMULATOR.myIsConseal; + myIsCrossedOut = EMPTY_EMULATOR.myIsCrossedOut; + myIsFraktur = EMPTY_EMULATOR.myIsFraktur; + myIsOverlined = EMPTY_EMULATOR.myIsOverlined; + mySerializedSgrStateProvider.drop(); + } + + /** + * @return true if emulator is in it's initial state + * @see #resetTerminal() + */ + public boolean isInitialState() { + return EMPTY_EMULATOR.equals(this); + } + + @Nullable + public Color getBackgroundColor() { + return myBackgroundColor == null ? null : myBackgroundColor.getColor(); + } + + public int getBackgroundColorIndex() { + return myBackgroundColor == null ? -1 : myBackgroundColor.getColorIndex(); + } + + @Nullable + public Color getForegroundColor() { + return myForegroundColor == null ? null : myForegroundColor.getColor(); + } + + public int getForegroundColorIndex() { + return myForegroundColor == null ? -1 : myForegroundColor.getColorIndex(); + } + + public boolean isInverse() { + return myIsInverse; + } + + @NotNull + public Underline getUnderline() { + return myUnderline; + } + + @NotNull + public FrameType getFrameType() { + return myFrameType; + } + + public boolean isCrossedOut() { + return myIsCrossedOut; + } + + @NotNull + public Boldness getBoldness() { + return myBoldness; + } + + public boolean isItalic() { + return myIsItalic; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AnsiTerminalEmulator emulator = (AnsiTerminalEmulator)o; + + if (myIsItalic != emulator.myIsItalic) return false; + if (myIsInverse != emulator.myIsInverse) return false; + if (myIsConseal != emulator.myIsConseal) return false; + if (myIsCrossedOut != emulator.myIsCrossedOut) return false; + if (myIsFraktur != emulator.myIsFraktur) return false; + if (myIsOverlined != emulator.myIsOverlined) return false; + if (myFont != emulator.myFont) return false; + if (myBoldness != emulator.myBoldness) return false; + if (myUnderline != emulator.myUnderline) return false; + if (myBlink != emulator.myBlink) return false; + if (myFrameType != emulator.myFrameType) return false; + if (!Objects.equals(myBackgroundColor, emulator.myBackgroundColor)) { + return false; + } + if (!Objects.equals(myForegroundColor, emulator.myForegroundColor)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = myFont.hashCode(); + result = 31 * result + myBoldness.hashCode(); + result = 31 * result + myUnderline.hashCode(); + result = 31 * result + myBlink.hashCode(); + result = 31 * result + myFrameType.hashCode(); + result = 31 * result + (myIsItalic ? 1 : 0); + result = 31 * result + (myIsInverse ? 1 : 0); + result = 31 * result + (myIsConseal ? 1 : 0); + result = 31 * result + (myIsCrossedOut ? 1 : 0); + result = 31 * result + (myIsFraktur ? 1 : 0); + result = 31 * result + (myIsOverlined ? 1 : 0); + result = 31 * result + (myBackgroundColor != null ? myBackgroundColor.hashCode() : 0); + result = 31 * result + (myForegroundColor != null ? myForegroundColor.hashCode() : 0); + return result; + } + + /** + * Decodes ANSI SGR sequences 38 && 48. Encodings may be: + *
    + *
  • 5;n - with index-based encoding
  • + *
  • 2;r;g;b - with red, green and blue parts
  • + *
+ */ + private static AnsiTerminalColor decodeColor(@NotNull Iterator encodedColorIterator) { + if (!encodedColorIterator.hasNext()) { + return null; + } + int encodingType = encodedColorIterator.next(); + if (encodingType == SGR_COLOR_ENCODING_RGB) { + Integer redCode = encodedColorIterator.hasNext() ? encodedColorIterator.next() : null; + Integer greenCode = encodedColorIterator.hasNext() ? encodedColorIterator.next() : null; + Integer blueCode = encodedColorIterator.hasNext() ? encodedColorIterator.next() : null; + if (redCode != null && greenCode != null && blueCode != null) { + return new RGBColor(redCode, greenCode, blueCode); + } + } + else if (encodingType == SGR_COLOR_ENCODING_INDEXED) { + Integer encodedColor = encodedColorIterator.hasNext() ? encodedColorIterator.next() : null; + if (encodedColor != null) { + return decode8BitColor(encodedColor); + } + } + + return null; + } + + /** + * Decodes index-encoded color from SGR + * + * @see 5;n - with index-based encoding + */ + private static AnsiTerminalColor decode8BitColor(int encodedColor) { + if (encodedColor >= 0 && encodedColor <= MAX_8BIT_COLOR_INDEX) { + return new EightBitColor(encodedColor); + } + else if (encodedColor >= COLOR_CUBE_MIN_INDEX && encodedColor <= 255) { + //16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) + //232-255: grayscale from black to white in 24 steps + return new EightBitRGBColor(encodedColor); + } + return null; + } + + public enum FrameType { + NO_FRAME(SGR_COMMAND_NO_FRAMED_ENCIRCLED, null), + FRAMED(SGR_COMMAND_FRAMED, EffectType.BOXED), + ENCIRCLED(SGR_COMMAND_ENCIRCLED, EffectType.ROUNDED_BOX); + + private static final FrameType DEFAULT = NO_FRAME; + /** + * SGR sequence code that should be used to switch to this option + */ + public final int sgrCode; + + @Nullable + public final EffectType effectType; + + FrameType(int sgrCode, @Nullable EffectType effectType) { + this.sgrCode = sgrCode; + this.effectType = effectType; + } + } + + public enum BlinkSpeed { + NO_BLINK(SGR_COMMAND_NO_BLINK), + SLOW_BLINK(SGR_COMMAND_BLINK_SLOW), + RAPID_BLINK(SGR_COMMAND_BLINK_RAPID); + + private static final BlinkSpeed DEFAULT = NO_BLINK; + /** + * SGR sequence code that should be used to switch to this option + */ + public final int sgrCode; + + BlinkSpeed(int sgrCode) { + this.sgrCode = sgrCode; + } + } + + public enum Boldness { + FAINT(SGR_COMMAND_FAINT), + NORMAL(SGR_COMMAND_NO_BOLD_FAINT), + BOLD(SGR_COMMAND_BOLD); + + private static final Boldness DEFAULT = NORMAL; + /** + * SGR sequence code that should be used to switch to this option + */ + public final int sgrCode; + + Boldness(int sgrCode) { + this.sgrCode = sgrCode; + } + } + + public enum Underline { + NO_UNDERLINE(SGR_COMMAND_NO_UNDERLINE, null), + SINGLE_UNDERLINE(SGR_COMMAND_UNDERLINE, LINE_UNDERSCORE), + DOUBLE_UNDERLINE(SGR_COMMAND_DOUBLE_UNDERLINE, BOLD_LINE_UNDERSCORE); + + private static final Underline DEFAULT = NO_UNDERLINE; + /** + * SGR sequence code that should be used to switch to this option + */ + public final int sgrCode; + + @Nullable + public final EffectType effectType; + + Underline(int sgrCode, @Nullable EffectType effectType) { + this.sgrCode = sgrCode; + this.effectType = effectType; + } + } + + public enum Font { + DEFAULT(SGR_COMMAND_PRIMARY_FONT), + ALT1(SGR_COMMAND_FONT1), + ALT2(SGR_COMMAND_FONT2), + ALT3(SGR_COMMAND_FONT3), + ALT4(SGR_COMMAND_FONT4), + ALT5(SGR_COMMAND_FONT5), + ALT6(SGR_COMMAND_FONT6), + ALT7(SGR_COMMAND_FONT7), + ALT8(SGR_COMMAND_FONT8), + ALT9(SGR_COMMAND_FONT9); + /** + * SGR sequence code that should be used to switch to this option + */ + public final int sgrCode; + + Font(int sgrCode) { + this.sgrCode = sgrCode; + } + } + + /** + * Represents a 24 bit color, encoded with {@link AnsiCommands#SGR_COLOR_ENCODING_RGB} + */ + private static final class RGBColor implements AnsiTerminalColor { + private final int myRed; + private final int myGreen; + private final int myBlue; + + private RGBColor(int red, int green, int blue) { + myRed = red; + myGreen = green; + myBlue = blue; + } + + @NotNull + @Override + public String getAnsiEncodedColor() { + return SGR_COLOR_ENCODING_RGB + ";" + myRed + ";" + myGreen + ";" + myBlue; + } + + + @Override + public int getColorIndex() { + return -1; + } + + @NotNull + @Override + public Color getColor() { + //noinspection UseJBColor + return new Color(myRed, myGreen, myBlue); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RGBColor color = (RGBColor)o; + + if (myRed != color.myRed) return false; + if (myGreen != color.myGreen) return false; + if (myBlue != color.myBlue) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myRed; + result = 31 * result + myGreen; + result = 31 * result + myBlue; + return result; + } + } + + /** + * Base class for index-based colors - 8bit and 8bit rgb colors + */ + private abstract static class IndexedAnsiTerminalColor implements AnsiTerminalColor { + private final int myColorIndex; + + protected IndexedAnsiTerminalColor(int colorIndex) { + myColorIndex = colorIndex; + } + + @Override + public int getColorIndex() { + return myColorIndex; + } + + @NotNull + @Override + public String getAnsiEncodedColor() { + return SGR_COLOR_ENCODING_INDEXED + ";" + getColorIndex(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + IndexedAnsiTerminalColor color = (IndexedAnsiTerminalColor)o; + + if (myColorIndex != color.myColorIndex) return false; + + return true; + } + + @Override + public int hashCode() { + return myColorIndex; + } + } + + /** + * Represents a simple indexed color for SGR commands: + *
    + *
  • {@link AnsiCommands#SGR_COMMAND_FG_COLOR0} - {@link AnsiCommands#SGR_COMMAND_FG_COLOR7}
  • + *
  • {@link AnsiCommands#SGR_COMMAND_BG_COLOR0} - {@link AnsiCommands#SGR_COMMAND_BG_COLOR7}
  • + *
  • {@link AnsiCommands#SGR_COMMAND_FG_COLOR8} - {@link AnsiCommands#SGR_COMMAND_FG_COLOR15}
  • + *
  • {@link AnsiCommands#SGR_COMMAND_BG_COLOR8} - {@link AnsiCommands#SGR_COMMAND_BG_COLOR15}
  • + *
+ * Also used for first 15 indexed colors from {@link AnsiCommands#SGR_COMMAND_FG_COLOR_ENCODED} and {@link AnsiCommands#SGR_COMMAND_BG_COLOR_ENCODED} + */ + private static class EightBitColor extends IndexedAnsiTerminalColor { + + private EightBitColor(int colorIndex) { + super(colorIndex); + if (colorIndex < 0 || colorIndex > MAX_8BIT_COLOR_INDEX) { + LOG.error("Wrong 8bit color index: " + colorIndex); + } + } + + @Nullable + @Override + public Color getColor() { + return null; + } + } + + /** + * Represents rgb colors encoded with {@link AnsiCommands#SGR_COLOR_ENCODING_INDEXED} from 16-231 and 232-255 + */ + private static final class EightBitRGBColor extends IndexedAnsiTerminalColor { + + // 8-bit color encoding for range 16-231 + private static final int[] CUBE_STEPS = { + 0x0, 0x5f, 0x87, 0xaf, 0xd7, 0xff + }; + // 8-bit grayscale encoding for range 232-255 + private static final int[] GRAYSCALE_STEPS = { + 0x08, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e, + 0x58, 0x62, 0x6c, 0x76, 0x80, 0x8a, 0x94, 0x9e, + 0xa8, 0xb2, 0xbc, 0xc6, 0xd0, 0xda, 0xe4, 0xee + }; + + private EightBitRGBColor(int colorIndex) { + super(colorIndex); + if (colorIndex < COLOR_CUBE_MIN_INDEX || colorIndex > 255) { + LOG.error("Wrong indexed RGB color index: " + colorIndex); + } + } + + @Nullable + @Override + public Color getColor() { + int colorIndex = getColorIndex(); + if (colorIndex >= COLOR_CUBE_MIN_INDEX && colorIndex < GRAY_MIN_INDEX) { + int encodedColor = colorIndex - COLOR_CUBE_MIN_INDEX; + //noinspection UseJBColor + return new Color(CUBE_STEPS[(encodedColor / 36) % 6], CUBE_STEPS[(encodedColor / 6) % 6], CUBE_STEPS[encodedColor % 6]); + } + else if (colorIndex >= GRAY_MIN_INDEX && colorIndex <= 255) { + int colorPart = GRAYSCALE_STEPS[colorIndex - GRAY_MIN_INDEX]; + //noinspection UseJBColor + return new Color(colorPart, colorPart, colorPart); + } + return null; + } + } +} diff --git a/platform/platform-api/src/com/intellij/execution/process/ColoredOutputTypeRegistry.java b/platform/platform-api/src/com/intellij/execution/process/ColoredOutputTypeRegistry.java index 68e39cc501ca..7669e9af0500 100644 --- a/platform/platform-api/src/com/intellij/execution/process/ColoredOutputTypeRegistry.java +++ b/platform/platform-api/src/com/intellij/execution/process/ColoredOutputTypeRegistry.java @@ -30,6 +30,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Map; /** @@ -113,12 +116,33 @@ public class ColoredOutputTypeRegistry { return streamOutputType; } ProcessOutputType newKey = new ProcessOutputType(completeAttribute, streamOutputType); - AnsiConsoleViewContentType contentType = createAnsiConsoleViewContentType(attribute); - ConsoleViewContentType.registerNewConsoleViewType(newKey, contentType); + ConsoleViewContentType.registerNewConsoleViewType(newKey, createAnsiConsoleViewContentType(attribute)); attrsToKeyMap.put(completeAttribute, newKey); return newKey; } + /** + * Creates an {@link ProcessOutputType} from the {@link AnsiTerminalEmulator terminal emulator state} and stream type. Output type may be used + * later to print to the console + */ + @NotNull + public ProcessOutputType getOutputType(@NotNull AnsiTerminalEmulator terminal, @NotNull Key streamType) { + Map attrsToKeyMap = ProcessOutputType.isStdout(streamType) ? myStdoutAttrsToKeyMap : myStderrAttrsToKeyMap; + String ansiSerializedState = terminal.getAnsiSerializedSGRState(); + ProcessOutputType key = attrsToKeyMap.get(ansiSerializedState); + if (key != null) { + return key; + } + + ProcessOutputType streamOutputType = streamType instanceof ProcessOutputType ? + (ProcessOutputType)streamType : (ProcessOutputType)ProcessOutputTypes.STDOUT; + + ProcessOutputType newKey = new ProcessOutputType(ansiSerializedState, streamOutputType); + ConsoleViewContentType.registerNewConsoleViewType(newKey, new AnsiConsoleViewContentType(terminal)); + attrsToKeyMap.put(ansiSerializedState, newKey); + return newKey; + } + /** * @deprecated use {@link #getOutputType(String, Key)} instead */ @@ -165,7 +189,7 @@ public class ColoredOutputTypeRegistry { } @NotNull - private static AnsiConsoleViewContentType createAnsiConsoleViewContentType(@NotNull String attribute) { + private static ConsoleViewContentType createAnsiConsoleViewContentType(@NotNull String attribute) { int foregroundColor = -1; int backgroundColor = -1; boolean inverse = false; @@ -224,30 +248,100 @@ public class ColoredOutputTypeRegistry { } private static class AnsiConsoleViewContentType extends ConsoleViewContentType { - private final int myBackgroundColor; - private final int myForegroundColor; + private final int myBackgroundColorIndex; + private final int myForegroundColorIndex; + @Nullable + private final Color myEnforcedBackgroundColor; + @Nullable + private final Color myEnforcedForegroundColor; private final boolean myInverse; - private final EffectType myEffectType; + @NotNull + private final List myEffectTypes; private final int myFontType; + private AnsiConsoleViewContentType(@NotNull String attribute, + int backgroundColorIndex, + int foregroundColorIndex, + @Nullable Color enforcedBackgroundColor, + @Nullable Color enforcedForegroundColor, + boolean inverse, + @NotNull List effectTypes, + int fontType) { + super(attribute, ConsoleViewContentType.NORMAL_OUTPUT_KEY); + myBackgroundColorIndex = backgroundColorIndex; + myEnforcedBackgroundColor = enforcedBackgroundColor; + myForegroundColorIndex = foregroundColorIndex; + myEnforcedForegroundColor = enforcedForegroundColor; + myInverse = inverse; + myEffectTypes = effectTypes.isEmpty() ? ContainerUtil.emptyList() : ContainerUtil.immutableList(effectTypes); + myFontType = fontType; + } + private AnsiConsoleViewContentType(@NotNull String attribute, int backgroundColor, int foregroundColor, boolean inverse, @Nullable EffectType effectType, int fontType) { - super(attribute, ConsoleViewContentType.NORMAL_OUTPUT_KEY); - myBackgroundColor = backgroundColor; - myForegroundColor = foregroundColor; - myInverse = inverse; - myEffectType = effectType; - myFontType = fontType; + this(attribute, backgroundColor, foregroundColor, null, null, inverse, + effectType == null ? Collections.emptyList() : Collections.singletonList(effectType), fontType); + } + + private AnsiConsoleViewContentType(@NotNull AnsiTerminalEmulator terminalEmulator) { + this(terminalEmulator.getAnsiSerializedSGRState(), + terminalEmulator.getBackgroundColorIndex(), + terminalEmulator.getForegroundColorIndex(), + terminalEmulator.getBackgroundColor(), + terminalEmulator.getForegroundColor(), + terminalEmulator.isInverse(), + computeEffectTypes(terminalEmulator), + computeAwtFont(terminalEmulator)); + } + + /** + * Computes effect types that can be represented by our editor + */ + @NotNull + private static List computeEffectTypes(@NotNull AnsiTerminalEmulator terminalEmulator) { + ArrayList result = ContainerUtil.newArrayList(); + AnsiTerminalEmulator.Underline underline = terminalEmulator.getUnderline(); + if (underline == AnsiTerminalEmulator.Underline.SINGLE_UNDERLINE) { + result.add(EffectType.LINE_UNDERSCORE); + } + else if (underline == AnsiTerminalEmulator.Underline.DOUBLE_UNDERLINE) { + result.add(EffectType.BOLD_LINE_UNDERSCORE); + } + if (terminalEmulator.isCrossedOut()) { + result.add(EffectType.STRIKEOUT); + } + AnsiTerminalEmulator.FrameType frameType = terminalEmulator.getFrameType(); + if (frameType == AnsiTerminalEmulator.FrameType.FRAMED) { + result.add(EffectType.BOXED); + } + else if (frameType == AnsiTerminalEmulator.FrameType.ENCIRCLED) { + result.add(EffectType.ROUNDED_BOX); + } + return result; + } + + /** + * Computes font style from boldness/italic flags + */ + private static int computeAwtFont(@NotNull AnsiTerminalEmulator terminalEmulator) { + int result = 0; + if (terminalEmulator.getBoldness() == AnsiTerminalEmulator.Boldness.BOLD) { + result = Font.BOLD; + } + if (terminalEmulator.isItalic()) { + result |= Font.ITALIC; + } + return result; } @Override public TextAttributes getAttributes() { TextAttributes attrs = new TextAttributes(); - attrs.setEffectType(myEffectType); + attrs.setEffectType(null); // re-setting default BOX if (myFontType != -1) { attrs.setFontType(myFontType); } @@ -257,21 +351,25 @@ public class ColoredOutputTypeRegistry { attrs.setForegroundColor(backgroundColor); attrs.setEffectColor(backgroundColor); attrs.setBackgroundColor(foregroundColor); + myEffectTypes.forEach(it -> attrs.withAdditionalEffect(it, backgroundColor)); } else { attrs.setForegroundColor(foregroundColor); attrs.setEffectColor(foregroundColor); attrs.setBackgroundColor(backgroundColor); + myEffectTypes.forEach(it -> attrs.withAdditionalEffect(it, foregroundColor)); } return attrs; } private Color getForegroundColor() { - return myForegroundColor != -1 ? getAnsiColor(myForegroundColor) : getDefaultForegroundColor(); + return myEnforcedForegroundColor != null ? myEnforcedForegroundColor : + myForegroundColorIndex != -1 ? getAnsiColor(myForegroundColorIndex) : getDefaultForegroundColor(); } private Color getBackgroundColor() { - return myBackgroundColor != -1 ? getAnsiColor(myBackgroundColor) : getDefaultBackgroundColor(); + return myEnforcedBackgroundColor != null ? myEnforcedBackgroundColor : + myBackgroundColorIndex != -1 ? getAnsiColor(myBackgroundColorIndex) : getDefaultBackgroundColor(); } } } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java index 9d0b065093d6..cca1f4753de9 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -676,10 +676,15 @@ public abstract class DialogWrapper { return myCheckBoxDoNotShowDialog != null && myCheckBoxDoNotShowDialog.isVisible() ? myCheckBoxDoNotShowDialog : null; } - private final JBValue BASE_BUTTON_GAP = new JBValue.Float(UIUtil.isUnderWin10LookAndFeel() ? 8 : 12); + private static final JBValue BASE_BUTTON_GAP = new JBValue.Float(UIUtil.isUnderWin10LookAndFeel() ? 8 : 12); @NotNull protected JPanel createButtonsPanel(@NotNull List buttons) { + return layoutButtonsPanel(buttons); + } + + @NotNull + public static JPanel layoutButtonsPanel(@NotNull List buttons) { JPanel buttonsPanel = new NonOpaquePanel(); buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.X_AXIS)); @@ -727,6 +732,26 @@ public abstract class DialogWrapper { * @see DialogWrapper#DEFAULT_ACTION */ protected JButton createJButtonForAction(Action action) { + JButton button = createJButtonForAction(action, getRootPane()); + + int mnemonic = button.getMnemonic(); + final Object name = action.getValue(Action.NAME); + if (mnemonic == KeyEvent.VK_Y && "Yes".equals(name)) { + myYesAction = action; + } + else if (mnemonic == KeyEvent.VK_N && "No".equals(name)) { + myNoAction = action; + } + + if (action.getValue(FOCUSED_ACTION) != null) { + myPreferredFocusedComponent = button; + } + + return button; + } + + @NotNull + public static JButton createJButtonForAction(@NotNull Action action, @Nullable JRootPane rootPane) { JButton button; if (action instanceof OptionAction && UISettings.getShadowInstance().getAllowMergeButtons()) { button = createJOptionsButton((OptionAction)action); @@ -749,24 +774,12 @@ public abstract class DialogWrapper { } button.setMnemonic(mnemonic); - final Object name = action.getValue(Action.NAME); - if (mnemonic == KeyEvent.VK_Y && "Yes".equals(name)) { - myYesAction = action; - } - else if (mnemonic == KeyEvent.VK_N && "No".equals(name)) { - myNoAction = action; - } - if (action.getValue(DEFAULT_ACTION) != null) { - if (!myPeer.isHeadless()) { - getRootPane().setDefaultButton(button); + if (rootPane != null) { + rootPane.setDefaultButton(button); } } - if (action.getValue(FOCUSED_ACTION) != null) { - myPreferredFocusedComponent = button; - } - return button; } diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java index 51d5f0fbd057..735b7ba238c9 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java @@ -109,6 +109,13 @@ public class SimpleColoredComponent extends JComponent implements Accessible, Co return new MyIterator(); } + @NotNull + public ColoredIterator iterator(int fromIndex) { + MyIterator iterator = new MyIterator(); + iterator.myIndex = fromIndex - 1; + return iterator; + } + @SuppressWarnings("unused") public boolean isIconOnTheRight() { return myIconOnTheRight; @@ -859,7 +866,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible, Co else if (attributes.isClickable()) { fgColor = ObjectUtils.notNull(attributes.getFgColor(), UIUtil.getLabelForeground()); Color bg = ObjectUtils.notNull(attributes.getBgColor(), UIUtil.getLabelBackground()); - drawClickableFrag(g, x1, x2, height, bg); + drawClickableFrag(g, x1, x2, height, bg, attributes.isHovered()); } else { continue; @@ -885,15 +892,17 @@ public class SimpleColoredComponent extends JComponent implements Accessible, Co g.fillRect(x, y, width, height); } - private static void drawClickableFrag(Graphics2D g, float x1, float x2, int height, Color bg) { + private static void drawClickableFrag(Graphics2D g, float x1, float x2, int height, Color bg, boolean hovered) { boolean darcula = UIUtil.isUnderDarcula(); Color c1 = darcula ? bg.brighter() : bg; Color c2 = darcula ? bg : bg.darker(); GraphicsConfig c = GraphicsUtil.setupRoundedBorderAntialiasing(g); g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); - g.setPaint(UIUtil.getGradientPaint(x1 + 1, 2, c1, x1 + 1, height - 5, c2)); RoundRectangle2D.Float shape = new RoundRectangle2D.Float(x1 + 1, 2, x2 - x1 - 2, height - 4, 4, 4); - g.fill(shape); + if (hovered) { + g.setPaint(UIUtil.getGradientPaint(x1 + 1, 2, c1, x1 + 1, height - 5, c2)); + g.fill(shape); + } g.setColor(new JBColor(Gray.xCC, new Color(0x757b80))); g.draw(shape); c.restore(); diff --git a/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java b/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java index 3d6b6132559d..7489aa63bc38 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java +++ b/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java @@ -271,7 +271,7 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene if (myAssigneeVisible) { myAssigneeCombo = new ComboBox<>(); - myAssigneeCombo.setRenderer((list, value, i, selected, focused) -> new JBLabel(value == null ? "" : value.getDisplayText())); + myAssigneeCombo.setRenderer(SimpleListCellRenderer.create("", Developer::getDisplayText)); myAssigneeCombo.setPrototypeDisplayValue(new Developer(0, StringUtil.repeatSymbol('-', 30))); myAssigneeCombo.addItemListener(e -> { if (e.getStateChange() == ItemEvent.SELECTED) { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java index 922854cb8833..ee3978a6f8fc 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java @@ -84,6 +84,7 @@ import static javax.swing.KeyStroke.getKeyStroke; public class Switcher extends AnAction implements DumbAware { private static final Key SWITCHER_KEY = Key.create("SWITCHER_KEY"); private static final Color SEPARATOR_COLOR = JBColor.namedColor("Popup.separatorColor", new JBColor(Gray.xC0, Gray.x4B)); + private static final String TOGGLE_CHECK_BOX_ACTION_ID = "SwitcherToggleCheckBox"; private static final int MINIMUM_HEIGHT = JBUI.scale(100); @@ -143,17 +144,17 @@ public class Switcher extends AnAction implements DumbAware { SwitcherPanel switcher = SWITCHER_KEY.get(project); if (switcher != null) { boolean sameShortcut = Comparing.equal(switcher.myTitle, title); - if (switcher.isCheckboxMode()) { - if (sameShortcut) { + if (sameShortcut) { + if (switcher.isCheckboxMode() && !ToggleCheckBoxAction.isEnabled()) { switcher.toggleShowEditedFiles(); } else { - switcher.setShowOnlyEditedFiles(onlyEdited); + switcher.goForward(); } return null; } - else if (sameShortcut) { - switcher.goForward(); + else if (switcher.isCheckboxMode()) { + switcher.setShowOnlyEditedFiles(onlyEdited); return null; } } @@ -171,6 +172,27 @@ public class Switcher extends AnAction implements DumbAware { return switcher; } + public static class ToggleCheckBoxAction extends DumbAwareAction implements DumbAware { + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + Project project = e.getProject(); + SwitcherPanel switcherPanel = SWITCHER_KEY.get(project); + if (switcherPanel != null) { + switcherPanel.toggleShowEditedFiles(); + } + } + + @Override + public void update(@NotNull AnActionEvent e) { + Project project = e.getProject(); + e.getPresentation().setEnabledAndVisible(SWITCHER_KEY.get(project) != null); + } + + static boolean isEnabled() { + return getActiveKeymapShortcuts(TOGGLE_CHECK_BOX_ACTION_ID).getShortcuts().length > 0; + } + } + public static class SwitcherPanel extends JPanel implements KeyListener, MouseListener, MouseMotionListener, DataProvider, QuickSearchComponent { final JBPopup myPopup; @@ -188,7 +210,6 @@ public class Switcher extends AnAction implements DumbAware { final Alarm myAlarm; final SwitcherSpeedSearch mySpeedSearch; final String myTitle; - final String myActionId; final int myBaseModifier; private JBPopup myHint; @@ -293,7 +314,6 @@ public class Switcher extends AnAction implements DumbAware { setLayout(new SwitcherLayouter()); this.project = project; myTitle = title; - myActionId = actionId; myPinned = pinned; mySpeedSearch = pinned ? new SwitcherSpeedSearch(this) : null; @@ -469,7 +489,9 @@ public class Switcher extends AnAction implements DumbAware { myClickListener.installOn(files); ScrollingUtil.ensureSelectionExists(files); - myShowOnlyEditedFilesCheckBox = new MyCheckBox(actionId, onlyEdited); + myShowOnlyEditedFilesCheckBox = new MyCheckBox(ToggleCheckBoxAction.isEnabled() ? TOGGLE_CHECK_BOX_ACTION_ID + : actionId, + onlyEdited); myTopPanel = createTopPanel(myShowOnlyEditedFilesCheckBox, isCheckboxMode() ? IdeBundle.message("title.popup.recent.files") : title, pinned); diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ViewInplaceCommentsAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ViewInplaceCommentsAction.java index deeaff4b1285..0245f52dc8a2 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ViewInplaceCommentsAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ViewInplaceCommentsAction.java @@ -5,8 +5,13 @@ import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.DumbAwareToggleAction; import com.intellij.openapi.wm.impl.IdeBackgroundUtil; +import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; +import javax.swing.*; +import java.awt.*; + /** * @author gregsh */ @@ -23,6 +28,14 @@ public class ViewInplaceCommentsAction extends DumbAwareToggleAction { @Override public void setSelected(@NotNull AnActionEvent e, boolean state) { UISettings.getInstance().setShowInplaceComments(state); + updateAllTreesCellsWidth(); IdeBackgroundUtil.repaintAllWindows(); } + + private static void updateAllTreesCellsWidth() { + for (JTree tree : UIUtil.uiTraverser(null).withRoots(Window.getWindows()).filter(JTree.class)) { + //noinspection deprecation + TreeUtil.invalidateCacheAndRepaint(tree.getUI()); + } + } } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNewLayout.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNewLayout.java index 51a1bb840b11..920ee4ed2a87 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNewLayout.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNewLayout.java @@ -108,7 +108,7 @@ public class PluginManagerConfigurableNewLayout private LinkComponent myMarketplaceSortByAction; private DefaultActionGroup myInstalledSearchGroup; - private Runnable myInstalledSearchCallback; + private Consumer myInstalledSearchCallback; private boolean myInstalledSearchSetState = true; @NotNull @@ -344,10 +344,10 @@ public class PluginManagerConfigurableNewLayout Map> customRepositoriesMap = pair.second; try { - addGroup(groups, allRepositoriesMap, "Featured", "is_featured_search=true", "sortBy:featured"); - addGroup(groups, allRepositoriesMap, "New and Updated", "orderBy=update+date", "sortBy:updated"); - addGroup(groups, allRepositoriesMap, "Top Downloads", "orderBy=downloads", "sortBy:downloads"); - addGroup(groups, allRepositoriesMap, "Top Rated", "orderBy=rating", "sortBy:rating"); + addGroup(groups, allRepositoriesMap, "Featured", "is_featured_search=true", "/sortBy:featured"); + addGroup(groups, allRepositoriesMap, "New and Updated", "orderBy=update+date", "/sortBy:updated"); + addGroup(groups, allRepositoriesMap, "Top Downloads", "orderBy=downloads", "/sortBy:downloads"); + addGroup(groups, allRepositoriesMap, "Top Rated", "orderBy=rating", "/sortBy:rating"); } catch (IOException e) { PluginManagerMain.LOG @@ -548,8 +548,8 @@ public class PluginManagerConfigurableNewLayout List queries = new ArrayList<>(); new SearchQueryParser.Marketplace(searchTextField.getText()) { @Override - protected void setSearchQuery(@NotNull String query) { - super.setSearchQuery(query); + protected void addToSearchQuery(@NotNull String query) { + super.addToSearchQuery(query); queries.add(query); } @@ -858,56 +858,38 @@ public class PluginManagerConfigurableNewLayout PluginsGroupComponent panel = new PluginsGroupComponent(new PluginListLayout(), new MultiSelectionEventHandler(), myNameListener, PluginManagerConfigurableNewLayout.this.mySearchListener, - descriptor -> new NewListPluginComponent(myPluginModel, descriptor, - false)); + descriptor -> new NewListPluginComponent(myPluginModel, descriptor, false)); panel.setSelectionListener(selectionListener); PluginManagerConfigurableNew.registerCopyProvider(panel); - myInstalledSearchCallback = () -> { - StringBuilder queryBuilder = new StringBuilder(); - - for (AnAction action : myInstalledSearchGroup.getChildren(null)) { - InstalledSearchOptionAction optionAction = (InstalledSearchOptionAction)action; - - if (optionAction.myState) { - if (queryBuilder.length() > 0) { - queryBuilder.append(" "); - } - - switch (optionAction.myOption) { - case Enabled: - queryBuilder.append("/enabled"); - break; - case Disabled: - queryBuilder.append("/disabled"); - break; - case Custom: - queryBuilder.append("/custom"); - break; - case Bundled: - queryBuilder.append("/bundled"); - break; - case Invalid: - queryBuilder.append("/invalid"); - break; - case NeedUpdate: - queryBuilder.append("/outdated"); - break; - case Deleted: - queryBuilder.append("/uninstalled"); - break; - case NeedRestart: - queryBuilder.append("/inactive"); - break; - } + myInstalledSearchCallback = updateAction -> { + List queries = new ArrayList<>(); + new SearchQueryParser.InstalledWithVendor(searchTextField.getText()) { + @Override + protected void addToSearchQuery(@NotNull String query) { + super.addToSearchQuery(query); + queries.add(query); } + + @Override + protected void handleAttribute(@NotNull String name, @NotNull String value, boolean invert) { + super.handleAttribute(name, value, invert); + queries.add("/" + name + (value.isEmpty() ? "" : ":" + value)); + } + }; + + if (updateAction.myState) { + queries.add(updateAction.getQuery()); + } + else { + queries.remove(updateAction.getQuery()); } try { myInstalledSearchSetState = false; - String query = queryBuilder.toString(); + String query = StringUtil.join(queries, " "); searchTextField.setTextIgnoreEvents(query); if (query.isEmpty()) { myInstalledTab.hideSearchPanel(); @@ -1079,7 +1061,7 @@ public class PluginManagerConfigurableNewLayout @Override public void setSelected(@NotNull AnActionEvent e, boolean state) { myState = state; - myInstalledSearchCallback.run(); + myInstalledSearchCallback.accept(this); } public void setState(@Nullable SearchQueryParser.Installed parser) { @@ -1115,6 +1097,29 @@ public class PluginManagerConfigurableNewLayout break; } } + + @NotNull + public String getQuery() { + switch (myOption) { + case Enabled: + return "/enabled"; + case Disabled: + return "/disabled"; + case Custom: + return "/custom"; + case Bundled: + return "/bundled"; + case Invalid: + return "/invalid"; + case NeedUpdate: + return "/outdated"; + case Deleted: + return "/uninstalled"; + case NeedRestart: + default: + return "/inactive"; + } + } } private static class GroupByActionGroup extends DefaultActionGroup implements CheckedActionGroup { diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginLogo.java b/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginLogo.java index ba44bab91f2c..765776414964 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginLogo.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginLogo.java @@ -14,6 +14,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.ui.JBColor; +import com.intellij.util.ArrayUtil; import com.intellij.util.Url; import com.intellij.util.Urls; import com.intellij.util.io.HttpRequests; @@ -51,11 +52,6 @@ public class PluginLogo { }); } - @NotNull - public static Icon getIcon(@NotNull IdeaPluginDescriptor descriptor, int width, int height) { - return null; - } - @NotNull public static Icon getIcon(@NotNull IdeaPluginDescriptor descriptor, boolean big, boolean jb, boolean error, boolean disabled) { return getIcon(descriptor).getIcon(big, jb, error, disabled); @@ -151,7 +147,7 @@ public class PluginLogo { } File[] files = libFile.listFiles(); - if (files == null || files.length == 0) { + if (ArrayUtil.isEmpty(files)) { putIcon(idPlugin, lazyIcon, null, null); return; } @@ -212,8 +208,8 @@ public class PluginLogo { } private static boolean tryLoadDirIcons(@NotNull String idPlugin, @NotNull LazyPluginLogoIcon lazyIcon, @NotNull File path) { - PluginLogoIconProvider light = tryLoadIcon(new File(path, PluginManagerCore.META_INF + PLUGIN_ICON)); - PluginLogoIconProvider dark = tryLoadIcon(new File(path, PluginManagerCore.META_INF + PLUGIN_ICON_DARK)); + PluginLogoIconProvider light = tryLoadIcon(path, true); + PluginLogoIconProvider dark = tryLoadIcon(path, false); if (light != null || dark != null) { putIcon(idPlugin, lazyIcon, light, dark); @@ -231,8 +227,8 @@ public class PluginLogo { return false; } try (ZipFile zipFile = new ZipFile(path)) { - PluginLogoIconProvider light = tryLoadIcon(zipFile, PLUGIN_ICON); - PluginLogoIconProvider dark = tryLoadIcon(zipFile, PLUGIN_ICON_DARK); + PluginLogoIconProvider light = tryLoadIcon(zipFile, true); + PluginLogoIconProvider dark = tryLoadIcon(zipFile, false); if (put || light != null || dark != null) { putIcon(idPlugin, lazyIcon, light, dark); return true; @@ -283,6 +279,11 @@ public class PluginLogo { }, ModalityState.any()); } + @Nullable + private static PluginLogoIconProvider tryLoadIcon(@NotNull File dirFile, boolean light) { + return tryLoadIcon(new File(dirFile, getIconFileName(light))); + } + @Nullable private static PluginLogoIconProvider tryLoadIcon(@NotNull File iconFile) { //noinspection IOResourceOpenedButNotSafelyClosed @@ -290,11 +291,16 @@ public class PluginLogo { } @Nullable - private static PluginLogoIconProvider tryLoadIcon(@NotNull ZipFile zipFile, @NotNull String name) { - ZipEntry iconEntry = zipFile.getEntry(PluginManagerCore.META_INF + name); + private static PluginLogoIconProvider tryLoadIcon(@NotNull ZipFile zipFile, boolean light) { + ZipEntry iconEntry = zipFile.getEntry(getIconFileName(light)); return iconEntry == null ? null : loadFileIcon(() -> zipFile.getInputStream(iconEntry)); } + @NotNull + static String getIconFileName(boolean light) { + return PluginManagerCore.META_INF + (light ? PLUGIN_ICON : PLUGIN_ICON_DARK); + } + @Nullable private static PluginLogoIconProvider loadFileIcon(@NotNull ThrowableComputable provider) { try { diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginLogoApi.java b/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginLogoApi.java new file mode 100644 index 000000000000..f3464214fb8e --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginLogoApi.java @@ -0,0 +1,174 @@ +// Copyright 2000-2019 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. +package com.intellij.ide.plugins.newui; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.plugins.IdeaPluginDescriptor; +import com.intellij.openapi.application.JetBrainsProtocolHandler; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.ui.JBColor; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * @author Alexander Lobas + */ +public class PluginLogoApi { + /** + * Direct load image from local dir or jar based plugin without background task and caches. + */ + @NotNull + public static Icon getIcon(@NotNull IdeaPluginDescriptor descriptor, int width, int height, @Nullable Logger logger) { + return new PluginLogoApi(width, height, logger).getIcon(descriptor); + } + + private final int myWidth; + private final int myHeight; + + private final Logger myLogger; + + private PluginLogoApi(int width, int height, @Nullable Logger logger) { + myWidth = width; + myHeight = height; + myLogger = logger; + } + + @NotNull + private Icon getIcon(@NotNull IdeaPluginDescriptor descriptor) { + File path = descriptor.getPath(); + + if (path == null) { + return getDefaultIcon(); + } + + if (path.isDirectory()) { + if (System.getProperty(JetBrainsProtocolHandler.REQUIRED_PLUGINS_KEY) != null) { + Icon icon = tryLoadDirIcon(new File(path, "classes")); + if (icon != null) { + return icon; + } + } + + Icon icon = tryLoadDirIcon(path); + if (icon != null) { + return icon; + } + + File libFile = new File(path, "lib"); + if (!libFile.exists() || !libFile.isDirectory()) { + return getDefaultIcon(); + } + + File[] files = libFile.listFiles(); + if (ArrayUtil.isEmpty(files)) { + return getDefaultIcon(); + } + + for (File file : files) { + Icon dirIcon = tryLoadDirIcon(file); + if (dirIcon != null) { + return dirIcon; + } + + Icon jarIcon = tryLoadJarIcon(file); + if (jarIcon != null) { + return jarIcon; + } + } + } + else { + Icon icon = tryLoadJarIcon(path); + if (icon != null) { + return icon; + } + } + + return getDefaultIcon(); + } + + @Nullable + private Icon tryLoadDirIcon(@NotNull File path) { + boolean light = JBColor.isBright(); + Icon icon = tryLoadIcon(path, light); + return icon == null ? tryLoadIcon(path, !light) : icon; + } + + @Nullable + private Icon tryLoadJarIcon(@NotNull File path) { + if (!FileUtil.isJarOrZip(path) || !path.exists()) { + return null; + } + try (ZipFile zipFile = new ZipFile(path)) { + boolean light = JBColor.isBright(); + Icon icon = tryLoadIcon(zipFile, light); + return icon == null ? tryLoadIcon(zipFile, !light) : icon; + } + catch (Exception e) { + if (myLogger != null) { + myLogger.error(e); + } + } + return null; + } + + @Nullable + private Icon tryLoadIcon(@NotNull File dirFile, boolean light) { + try { + File iconFile = new File(dirFile, PluginLogo.getIconFileName(light)); + return iconFile.exists() && iconFile.length() > 0 ? loadFileIcon(new FileInputStream(iconFile)) : null; + } + catch (IOException e) { + if (myLogger != null) { + myLogger.error(e); + } + return null; + } + } + + @Nullable + private Icon tryLoadIcon(@NotNull ZipFile zipFile, boolean light) { + try { + ZipEntry iconEntry = zipFile.getEntry(PluginLogo.getIconFileName(light)); + return iconEntry == null ? null : loadFileIcon(zipFile.getInputStream(iconEntry)); + } + catch (IOException e) { + if (myLogger != null) { + myLogger.error(e); + } + return null; + } + } + + @NotNull + private Icon loadFileIcon(@NotNull InputStream stream) throws IOException { + return HiDPIPluginLogoIcon.loadSVG(stream, myWidth, myHeight); + } + + private Icon getDefaultIcon() { + if (AllIcons.Plugins.PluginLogo instanceof IconLoader.CachedImageIcon) { + URL url = ((IconLoader.CachedImageIcon)AllIcons.Plugins.PluginLogo).getURL(); + if (url != null) { + try { + return HiDPIPluginLogoIcon.loadSVG(url.openStream(), myWidth, myHeight); + } + catch (IOException e) { + if (myLogger != null) { + myLogger.error(e); + } + } + } + } + return AllIcons.Plugins.PluginLogo; + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchQueryParser.java b/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchQueryParser.java index d9e9b453d2b7..d0487704e24e 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchQueryParser.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchQueryParser.java @@ -94,7 +94,7 @@ public abstract class SearchQueryParser { return; } if (size == 1) { - setSearchQuery(words.get(0)); + addToSearchQuery(words.get(0)); return; } @@ -108,22 +108,23 @@ public abstract class SearchQueryParser { handleAttribute(name, words.get(index++), invert); } else { - searchQuery = query; + addToSearchQuery(query); return; } } - else if (searchQuery == null) { - setSearchQuery(name); - } else { - setSearchQuery(query); - return; + addToSearchQuery(name); } } } - protected void setSearchQuery(@NotNull String query) { - searchQuery = query; + protected void addToSearchQuery(@NotNull String query) { + if (searchQuery == null) { + searchQuery = query; + } + else { + searchQuery += " " + query; + } } protected abstract void handleAttribute(@NotNull String name, @NotNull String value, boolean invert); @@ -244,12 +245,8 @@ public abstract class SearchQueryParser { else if (word.startsWith("-#")) { handleAttribute(word.substring(2), "", true); } - else if (searchQuery == null) { - searchQuery = word; - } else { - searchQuery = query; - break; + addToSearchQuery(word); } } parseEnd(); @@ -319,7 +316,7 @@ public abstract class SearchQueryParser { vendors.add(words.get(index++)); } else { - searchQuery = query; + addToSearchQuery(query); break; } } @@ -327,12 +324,8 @@ public abstract class SearchQueryParser { handleAttribute(name.substring(1), "", false); } } - else if (searchQuery == null) { - searchQuery = name; - } else { - searchQuery = query; - break; + addToSearchQuery(name); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java b/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java index 29cdff3a3e4d..d3d22f4b9034 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java @@ -546,7 +546,7 @@ public class AppearanceConfigurable implements SearchableConfigurable { } } - private static class AAListCellRenderer extends JLabel implements ListCellRenderer { + private static class AAListCellRenderer extends SimpleListCellRenderer { private static final Object SUBPIXEL_HINT = GraphicsUtil.createAATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); private static final Object GREYSCALE_HINT = GraphicsUtil.createAATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_ON); @@ -557,7 +557,7 @@ public class AppearanceConfigurable implements SearchableConfigurable { } @Override - public Component getListCellRendererComponent(JList list, AntialiasingType value, int i, boolean s, boolean f) { + public void customize(JList list, AntialiasingType value, int index, boolean selected, boolean hasFocus) { if (value == AntialiasingType.SUBPIXEL) { GraphicsUtil.setAntialiasingType(this, SUBPIXEL_HINT); } @@ -574,8 +574,6 @@ public class AppearanceConfigurable implements SearchableConfigurable { } setText(String.valueOf(value)); - - return this; } } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java index cb91f6ee83ea..df88daadf1fd 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java @@ -539,18 +539,26 @@ public final class LafManagerImpl extends LafManager implements PersistentStateC defaults.put("TreeUI", "com.intellij.ui.tree.ui.DefaultTreeUI"); defaults.put("Tree.repaintWholeRow", true); } - Icon collapsedIcon = defaults.getIcon("Tree.collapsedIcon"); - if (collapsedIcon == null || collapsedIcon instanceof UIResource) { + if (isUnsupported(defaults.getIcon("Tree.collapsedIcon"))) { defaults.put("Tree.collapsedIcon", LafIconLookup.getIcon("treeCollapsed")); defaults.put("Tree.collapsedSelectedIcon", LafIconLookup.getSelectedIcon("treeCollapsed")); } - Icon expandedIcon = defaults.getIcon("Tree.expandedIcon"); - if (expandedIcon == null || collapsedIcon instanceof UIResource) { + if (isUnsupported(defaults.getIcon("Tree.expandedIcon"))) { defaults.put("Tree.expandedIcon", LafIconLookup.getIcon("treeExpanded")); defaults.put("Tree.expandedSelectedIcon", LafIconLookup.getSelectedIcon("treeExpanded")); } } + /** + * @param icon an icon retrieved from L&F + * @return {@code true} if an icon is not specified or if it is declared in some Swing L&F + * (such icons do not have a variant to paint in selected row) + */ + private static boolean isUnsupported(@Nullable Icon icon) { + String name = icon == null ? null : icon.getClass().getName(); + return name == null || name.startsWith("javax.swing.plaf.") || name.startsWith("com.sun.java.swing.plaf."); + } + private static void patchHiDPI(UIDefaults defaults) { Object prevScaleVal = defaults.get("hidpi.scaleFactor"); // used to normalize previously patched values diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties index 659607a77057..9185b800e6a9 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties @@ -207,6 +207,10 @@ Spinner.editorBorderPainted=false SplitPane.highlight=3c3f41 TreeUI=com.intellij.ide.ui.laf.darcula.ui.DarculaTreeUI +Tree.collapsedIcon=/com/intellij/ide/ui/laf/icons/darcula/treeCollapsed.svg +Tree.expandedIcon=/com/intellij/ide/ui/laf/icons/darcula/treeExpanded.svg +Tree.collapsedSelectedIcon=/com/intellij/ide/ui/laf/icons/darcula/treeCollapsedSelected.svg +Tree.expandedSelectedIcon=/com/intellij/ide/ui/laf/icons/darcula/treeExpandedSelected.svg Tree.paintLines=false Tree.hash=505355 @@ -279,4 +283,8 @@ DragAndDrop.areaBackground=404a57 DragAndDrop.areaBorderColor=4f73a8 DragAndDrop.areaForeground=bababa -CompletionPopup.nonFocusedState=true \ No newline at end of file +CompletionPopup.nonFocusedState=true + +NewClass.Panel.background=45494a +NewClass.SearchField.background=3c3f41 +NewClass.separatorWidth=10 \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties index 7863d29e6b83..608865362543 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties @@ -184,6 +184,10 @@ SplitPane.highlight=f2f2f2 TreeUI=com.intellij.ide.ui.laf.darcula.ui.DarculaTreeUI Tree.background=ffffff +Tree.collapsedIcon=/com/intellij/ide/ui/laf/icons/intellij/treeCollapsed.svg +Tree.expandedIcon=/com/intellij/ide/ui/laf/icons/intellij/treeExpanded.svg +Tree.collapsedSelectedIcon=/com/intellij/ide/ui/laf/icons/intellij/treeCollapsedSelected.svg +Tree.expandedSelectedIcon=/com/intellij/ide/ui/laf/icons/intellij/treeExpandedSelected.svg Tree.paintLines=false Tree.hash=E6E6E6 Tree.textBackground=ffffff @@ -277,4 +281,8 @@ DragAndDrop.areaBackground=e1ebf5 DragAndDrop.areaBorderColor=8ab2de DragAndDrop.areaForeground=787878 -CompletionPopup.nonFocusedState=true \ No newline at end of file +CompletionPopup.nonFocusedState=true + +NewClass.Panel.background=f2f2f2 +NewClass.SearchField.background=ffffff +NewClass.separatorWidth=10 \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_mac.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_mac.properties index ab5768ea381d..280456daaece 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_mac.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_mac.properties @@ -101,6 +101,10 @@ TabbedPane.tabFillStyle=underline TableHeader.cellBorder=2,2,2,2 +Tree.collapsedIcon=/com/intellij/ide/ui/laf/icons/treeCollapsed.svg +Tree.expandedIcon=/com/intellij/ide/ui/laf/icons/treeExpanded.svg +Tree.collapsedSelectedIcon=/com/intellij/ide/ui/laf/icons/treeCollapsedSelected.svg +Tree.expandedSelectedIcon=/com/intellij/ide/ui/laf/icons/treeExpandedSelected.svg Tree.paintLines=false Tree.hash=E6E6E6 Tree.rowHeight=20 diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties index ab4a05f19aab..dea0423e848e 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties @@ -174,6 +174,10 @@ SearchEverywhere.shortcutForeground=a7c1db TreeUI=com.intellij.ide.ui.laf.darcula.ui.DarculaTreeUI Tree.background=ffffff +Tree.collapsedIcon=/com/intellij/ide/ui/laf/icons/win10/treeCollapsed.svg +Tree.expandedIcon=/com/intellij/ide/ui/laf/icons/win10/treeExpanded.svg +Tree.collapsedSelectedIcon=/com/intellij/ide/ui/laf/icons/win10/treeCollapsedSelected.svg +Tree.expandedSelectedIcon=/com/intellij/ide/ui/laf/icons/win10/treeExpandedSelected.svg Tree.paintLines=false Tree.hash=E6E6E6 Tree.rowHeight=0 @@ -264,4 +268,8 @@ SearchEverywhere.SearchField.infoForeground=808080 SearchEverywhere.Advertiser.foreground=808080 SearchEverywhere.Advertiser.background=f2f2f2 -CompletionPopup.nonFocusedState=true \ No newline at end of file +CompletionPopup.nonFocusedState=true + +NewClass.Panel.background=f2f2f2 +NewClass.SearchField.background=ffffff +NewClass.separatorWidth=10 \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java index dd4502024f01..fdaed9107432 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeVersion.java @@ -1,7 +1,6 @@ // Copyright 2000-2019 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. package com.intellij.openapi.diff.impl.mergeTool; -import com.intellij.configurationStore.StoreReloadManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.undo.DocumentReference; @@ -14,17 +13,12 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.projectImport.ProjectOpenProcessor; -import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.util.Collection; -import java.util.Set; @Deprecated public interface MergeVersion { @@ -88,31 +82,6 @@ public interface MergeVersion { setDocumentText(myDocument, text, DiffBundle.message("save.merge.result.command.name"), project); FileDocumentManager.getInstance().saveDocument(myDocument); - reportProjectFileChangeIfNeeded(project, getFile()); - } - - public static void reportProjectFileChangeIfNeeded(@Nullable Project project, @Nullable VirtualFile file) { - if (project != null && file != null && !file.isDirectory() && (ProjectUtil.isProjectOrWorkspaceFile(file) || isProjectFile(file))) { - StoreReloadManager.getInstance().saveChangedProjectFile(file, project); - } - } - - @Nullable - public static Runnable prepareToReportChangedProjectFiles(@NotNull final Project project, @NotNull Collection files) { - final Set vfs = new THashSet<>(); - for (VirtualFile file : files) { - if (file != null && !file.isDirectory()) { - if (ProjectUtil.isProjectOrWorkspaceFile(file) || isProjectFile(file)) { - vfs.add(file); - } - } - } - return vfs.isEmpty() ? null : () -> { - StoreReloadManager storeReloadManager = StoreReloadManager.getInstance(); - for (VirtualFile vf : vfs) { - storeReloadManager.saveChangedProjectFile(vf, project); - } - }; } @Override @@ -120,11 +89,6 @@ public interface MergeVersion { ApplicationManager.getApplication().runWriteAction(() -> doRestoreOriginalContent(project)); } - public static boolean isProjectFile(VirtualFile file) { - final ProjectOpenProcessor importProvider = ProjectOpenProcessor.getImportProvider(file); - return importProvider != null && importProvider.lookForProjectsInDirectory(); - } - protected void doRestoreOriginalContent(@Nullable Project project) { setDocumentText(myDocument, myTextBeforeMerge, "", project); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index a41aa9a06531..98a804c06184 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -591,12 +591,13 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse AffineTransform old = setMirrorTransformIfNeeded(g, getLineNumberAreaOffset(), getLineNumberAreaWidth()); try { - int caretLine = convertor.execute(myEditor.getCaretModel().getLogicalPosition().line); + int caretLogicalLine = myEditor.getCaretModel().getLogicalPosition().line; VisualLinesIterator visLinesIterator = new VisualLinesIterator(myEditor, startVisualLine); while (!visLinesIterator.atEnd() && visLinesIterator.getVisualLine() <= endVisualLine) { if (!visLinesIterator.startsWithSoftWrap()) { - int logLine = convertor.execute(visLinesIterator.getStartLogicalLine()); - if (logLine >= 0) { + int logicalLine = visLinesIterator.getStartLogicalLine(); + int lineToDisplay = convertor.execute(logicalLine); + if (lineToDisplay >= 0) { int startY = visLinesIterator.getY(); if (myEditor.isInDistractionFreeMode()) { Color fgColor = myTextFgColors.get(visLinesIterator.getVisualLine()); @@ -605,11 +606,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse g.setColor(color); } - if (colorUnderCaretRow != null && caretLine == logLine) { + if (colorUnderCaretRow != null && caretLogicalLine == logicalLine) { g.setColor(colorUnderCaretRow); } - String s = String.valueOf(logLine + 1); + String s = String.valueOf(lineToDisplay + 1); int textOffset = isMirrored() ? offset - getLineNumberAreaWidth() - 1 : offset - g.getFontMetrics().stringWidth(s); diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java index f9161251ecff..c421c10c563c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java @@ -212,7 +212,7 @@ public class SettingsTreeView extends JComponent implements Accessible, Disposab @Override public void paintIcon(Component c, Graphics g, int x, int y) { - if (expanded != null) control.paint(g, x, y, getIconWidth(), getIconHeight(), expanded, false); + if (expanded != null) control.paint(c, g, x, y, getIconWidth(), getIconHeight(), expanded, false); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java index 2a19a27ee772..aa3193cb524e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java @@ -14,10 +14,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerListener; import com.intellij.openapi.ui.popup.util.PopupUtil; -import com.intellij.openapi.util.ActionCallback; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.WindowStateService; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.*; import com.intellij.openapi.wm.ex.LayoutFocusTraversalPolicyExt; @@ -51,6 +48,7 @@ public class FrameWrapper implements Disposable, DataProvider { private String myTitle = ""; private List myImages = null; private boolean myCloseOnEsc = false; + private BooleanGetter myOnCloseHandler; private Window myFrame; private final Map myDataMap = ContainerUtil.newHashMap(); private Project myProject; @@ -119,10 +117,17 @@ public class FrameWrapper implements Disposable, DataProvider { } if (frame instanceof JFrame) { - ((JFrame)frame).setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - } else { - ((JDialog)frame).setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + ((JFrame)frame).setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); } + else { + ((JDialog)frame).setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + } + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + close(); + } + }); UIUtil.decorateWindowHeader(((RootPaneContainer)frame).getRootPane()); @@ -180,6 +185,13 @@ public class FrameWrapper implements Disposable, DataProvider { } public void close() { + if (myOnCloseHandler != null && !myOnCloseHandler.get()) return; + + // if you remove this line problems will start happen on Mac OS X + // 2 projects opened, call Cmd+D on the second opened project and then Esc. + // Weird situation: 2nd IdeFrame will be active, but focus will be somewhere inside the 1st IdeFrame + // App is unusable until Cmd+Tab, Cmd+tab + FrameWrapper.this.myFrame.setVisible(false); Disposer.dispose(this); } @@ -240,11 +252,6 @@ public class FrameWrapper implements Disposable, DataProvider { @Override public void actionPerformed(ActionEvent e) { if (!PopupUtil.handleEscKeyEvent()) { - // if you remove this line problems will start happen on Mac OS X - // 2 projects opened, call Cmd+D on the second opened project and then Esc. - // Weird situation: 2nd IdeFrame will be active, but focus will be somewhere inside the 1st IdeFrame - // App is unusable until Cmd+Tab, Cmd+tab - FrameWrapper.this.myFrame.setVisible(false); close(); } } @@ -313,6 +320,10 @@ public class FrameWrapper implements Disposable, DataProvider { myImages = images; } + public void setOnCloseHandler(BooleanGetter onCloseHandler) { + myOnCloseHandler = onCloseHandler; + } + protected void loadFrameState() { final Window frame = getFrame(); if (myDimensionKey != null && !WindowStateService.getInstance().loadStateFor(myProject, myDimensionKey, frame)) { @@ -361,7 +372,6 @@ public class FrameWrapper implements Disposable, DataProvider { MouseGestureManager.getInstance().add(this); setFocusTraversalPolicy(new LayoutFocusTraversalPolicyExt()); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); } @Override @@ -452,7 +462,6 @@ public class FrameWrapper implements Disposable, DataProvider { setBackground(UIUtil.getPanelBackground()); MouseGestureManager.getInstance().add(this); setFocusTraversalPolicy(new LayoutFocusTraversalPolicyExt()); - setDefaultCloseOperation(DISPOSE_ON_CLOSE); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/WindowWrapperBuilder.java b/platform/platform-impl/src/com/intellij/openapi/ui/WindowWrapperBuilder.java index 800dc5786130..5a30f79c0b68 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/WindowWrapperBuilder.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/WindowWrapperBuilder.java @@ -3,6 +3,7 @@ package com.intellij.openapi.ui; import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.WindowWrapper.Mode; +import com.intellij.openapi.util.BooleanGetter; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; @@ -26,6 +27,7 @@ public class WindowWrapperBuilder { @Nullable private Computable myPreferredFocusedComponent; @Nullable private String myDimensionServiceKey; @Nullable private Runnable myOnShowCallback; + @Nullable private BooleanGetter myOnCloseHandler; public WindowWrapperBuilder(@NotNull Mode mode, @NotNull JComponent component) { myMode = mode; @@ -74,6 +76,12 @@ public class WindowWrapperBuilder { return this; } + @NotNull + public WindowWrapperBuilder setOnCloseHandler(@NotNull BooleanGetter handler) { + myOnCloseHandler = handler; + return this; + } + @NotNull public WindowWrapper build() { switch (myMode) { @@ -107,7 +115,7 @@ public class WindowWrapperBuilder { myDialog = builder.myParent != null ? new MyDialogWrapper(builder.myParent, builder.myComponent) : new MyDialogWrapper(builder.myProject, builder.myComponent); - myDialog.setParameters(builder.myDimensionServiceKey, builder.myPreferredFocusedComponent); + myDialog.setParameters(builder.myDimensionServiceKey, builder.myPreferredFocusedComponent, builder.myOnCloseHandler); installOnShowCallback(myDialog.getWindow(), builder.myOnShowCallback); @@ -178,6 +186,7 @@ public class WindowWrapperBuilder { @NotNull private final JComponent myComponent; @Nullable private String myDimensionServiceKey; @Nullable private Computable myPreferredFocusedComponent; + @Nullable private BooleanGetter myOnCloseHandler; MyDialogWrapper(@Nullable Project project, @NotNull JComponent component) { super(project, true); @@ -190,9 +199,11 @@ public class WindowWrapperBuilder { } public void setParameters(@Nullable String dimensionServiceKey, - @Nullable Computable preferredFocusedComponent) { + @Nullable Computable preferredFocusedComponent, + @Nullable BooleanGetter onCloseHandler) { myDimensionServiceKey = dimensionServiceKey; myPreferredFocusedComponent = preferredFocusedComponent; + myOnCloseHandler = onCloseHandler; } @Nullable @@ -231,6 +242,12 @@ public class WindowWrapperBuilder { if (myPreferredFocusedComponent != null) return myPreferredFocusedComponent.compute(); return super.getPreferredFocusedComponent(); } + + @Override + public void doCancelAction() { + if (myOnCloseHandler != null && !myOnCloseHandler.get()) return; + super.doCancelAction(); + } } } @@ -251,6 +268,7 @@ public class WindowWrapperBuilder { myFrame = new MyFrameWrapper(builder.myProject, builder.myDimensionServiceKey); myFrame.setParameters(builder.myPreferredFocusedComponent); + myFrame.setOnCloseHandler(builder.myOnCloseHandler); myOnShowCallback = builder.myOnShowCallback; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java index 296edf3b41f4..93c906557c19 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshQueueImpl.java @@ -81,7 +81,7 @@ public class RefreshQueueImpl extends RefreshQueue implements Disposable { myEventCounter.eventHappened(session); } - private void doScan(RefreshSessionImpl session) { + private void doScan(@NotNull RefreshSessionImpl session) { try { updateSessionMap(session, true); session.scan(); @@ -91,7 +91,7 @@ public class RefreshQueueImpl extends RefreshQueue implements Disposable { } } - private void updateSessionMap(RefreshSession session, boolean add) { + private void updateSessionMap(@NotNull RefreshSession session, boolean add) { long id = session.getId(); if (id != 0) { synchronized (mySessions) { @@ -135,5 +135,9 @@ public class RefreshQueueImpl extends RefreshQueue implements Disposable { } @Override - public void dispose() { } + public void dispose() { + synchronized (mySessions) { + mySessions.forEachValue(session -> { ((RefreshSessionImpl)session).cancel(); return true; }); + } + } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java index 87a55a0130e5..bc69bf3dbe73 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java @@ -144,6 +144,7 @@ public class RefreshWorker { @NotNull TObjectHashingStrategy strategy, @NotNull VirtualDirectoryImpl dir) { while (true) { + checkCancelled(dir); // obtaining directory snapshot Pair result = LocalFileSystemRefreshWorker.getDirectorySnapshot(persistence, dir); if (result == null) return; @@ -189,6 +190,7 @@ public class RefreshWorker { // generating events unless a directory was changed in between boolean hasEvents = ReadAction.compute(() -> { + checkCancelled(dir); if (!Arrays.equals(persistedNames, persistence.list(dir)) || !Arrays.equals(children, dir.getChildren())) { if (LOG.isTraceEnabled()) LOG.trace("retry: " + dir); return false; @@ -206,6 +208,7 @@ public class RefreshWorker { } for (Pair pair : updatedMap) { + checkCancelled(dir); VirtualFile child = pair.first; FileAttributes childAttributes = pair.second; if (childAttributes != null) { @@ -229,6 +232,7 @@ public class RefreshWorker { @NotNull TObjectHashingStrategy strategy, @NotNull VirtualDirectoryImpl dir) { while (true) { + checkCancelled(dir); // obtaining directory snapshot Pair, List> result = ReadAction.compute(() -> pair(dir.getCachedChildren(), dir.getSuspiciousNames())); @@ -263,6 +267,7 @@ public class RefreshWorker { // generating events unless a directory was changed in between boolean hasEvents = ReadAction.compute(() -> { + checkCancelled(dir); if (!cached.equals(dir.getCachedChildren()) || !wanted.equals(dir.getSuspiciousNames())) { if (LOG.isTraceEnabled()) LOG.trace("retry: " + dir); return false; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt index 11ee9c6171e8..a21598be3d3b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/customFrameDecorations/header/CustomHeader.kt @@ -5,6 +5,7 @@ import com.intellij.icons.AllIcons import com.intellij.jdkEx.JdkEx import com.intellij.openapi.Disposable import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.io.WindowsRegistryUtil import com.intellij.openapi.wm.impl.IdeRootPane import com.intellij.openapi.wm.impl.customFrameDecorations.CustomFrameTitleButtons import com.intellij.ui.AppUIUtil @@ -97,7 +98,7 @@ abstract class CustomHeader(private val window: Window) : JPanel(), Disposable { onClose() } - override fun windowStateChanged(e: java.awt.event.WindowEvent?) { + override fun windowStateChanged(e: WindowEvent?) { windowStateChanged() } } @@ -216,9 +217,12 @@ abstract class CustomHeader(private val window: Window) : JPanel(), Disposable { inner class CustomFrameTopBorder(val isTopNeeded: ()-> Boolean = {true}, val isBottomNeeded: ()-> Boolean = {false}) : Border { val thickness = 1 private val menuBarBorderColor: Color = JBColor.namedColor("MenuBar.borderColor", JBColor(Gray.xCD, Gray.x51)) + private val affectsBorders: Boolean = Toolkit.getDefaultToolkit().getDesktopProperty("win.dwm.colorizationColor.affects.borders") as Boolean? ?: true private val activeColor = Toolkit.getDefaultToolkit().getDesktopProperty("win.dwm.colorizationColor") as Color? ?: Toolkit.getDefaultToolkit().getDesktopProperty("win.frame.activeBorderColor") as Color? ?: menuBarBorderColor + private val windowsVersion = WindowsRegistryUtil.readRegistryValue("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ReleaseId") + fun repaintBorder() { val borderInsets = getBorderInsets(this@CustomHeader) @@ -227,7 +231,7 @@ abstract class CustomHeader(private val window: Window) : JPanel(), Disposable { } override fun paintBorder(c: Component, g: Graphics, x: Int, y: Int, width: Int, height: Int) { - if (isTopNeeded() && myActive) { + if (isTopNeeded() && myActive && isAffectsBorder()) { g.color = activeColor LinePainter2D.paint(g as Graphics2D, x.toDouble(), y.toDouble(), width.toDouble(), y.toDouble()) } @@ -239,9 +243,16 @@ abstract class CustomHeader(private val window: Window) : JPanel(), Disposable { } } + private fun isAffectsBorder(): Boolean { + if(windowsVersion.isNullOrEmpty()) return true + + val winVersion = windowsVersion.toIntOrNull() ?: return affectsBorders + return if(winVersion >= 1809) affectsBorders else true + } + override fun getBorderInsets(c: Component): Insets { val scale = JBUI.scale(thickness) - return Insets(if (isTopNeeded()) thickness else 0, 0, if (isBottomNeeded()) scale else 0, 0) + return Insets(if (isTopNeeded() && isAffectsBorder()) thickness else 0, 0, if (isBottomNeeded()) scale else 0, 0) } override fun isBorderOpaque(): Boolean { diff --git a/platform/platform-impl/src/com/intellij/ui/tree/ui/ClassicPainter.java b/platform/platform-impl/src/com/intellij/ui/tree/ui/ClassicPainter.java index e71ff6f2a7d0..0cdd69290578 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/ui/ClassicPainter.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/ui/ClassicPainter.java @@ -8,6 +8,7 @@ import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; @@ -50,7 +51,7 @@ final class ClassicPainter implements Control.Painter { } @Override - public void paint(@NotNull Graphics g, int x, int y, int width, int height, + public void paint(@NotNull Component c, @NotNull Graphics g, int x, int y, int width, int height, @NotNull Control control, int depth, boolean leaf, boolean expanded, boolean selected) { if (depth <= 0) return; // do not paint boolean paintLines = getPaintLines(); @@ -72,7 +73,7 @@ final class ClassicPainter implements Control.Painter { } } if (leaf) return; // do not paint control for a leaf node - control.paint(g, controlX, y, controlWidth, height, expanded, selected); + control.paint(c, g, controlX, y, controlWidth, height, expanded, selected); } private boolean getPaintLines() { diff --git a/platform/platform-impl/src/com/intellij/ui/tree/ui/CompactPainter.java b/platform/platform-impl/src/com/intellij/ui/tree/ui/CompactPainter.java index 3b342274b2db..8775a5c61cca 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/ui/CompactPainter.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/ui/CompactPainter.java @@ -5,6 +5,7 @@ import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.awt.Component; import java.awt.Graphics; final class CompactPainter implements Control.Painter { @@ -39,7 +40,7 @@ final class CompactPainter implements Control.Painter { } @Override - public void paint(@NotNull Graphics g, int x, int y, int width, int height, + public void paint(@NotNull Component c, @NotNull Graphics g, int x, int y, int width, int height, @NotNull Control control, int depth, boolean leaf, boolean expanded, boolean selected) { if (depth <= 0) return; // do not paint if (!paintLines && leaf) return; // nothing to paint @@ -61,7 +62,7 @@ final class CompactPainter implements Control.Painter { } } if (leaf) return; // do not paint control for a leaf node - control.paint(g, controlX, y, controlWidth, height, expanded, selected); + control.paint(c, g, controlX, y, controlWidth, height, expanded, selected); } private int getLeftIndent() { diff --git a/platform/platform-impl/src/com/intellij/ui/tree/ui/Control.java b/platform/platform-impl/src/com/intellij/ui/tree/ui/Control.java index e9b62a20c0d7..4f71ffa843a6 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/ui/Control.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/ui/Control.java @@ -4,6 +4,7 @@ package com.intellij.ui.tree.ui; import com.intellij.ui.JBColor; import org.jetbrains.annotations.NotNull; +import java.awt.Component; import java.awt.Graphics; import javax.swing.Icon; @@ -15,7 +16,7 @@ public interface Control { int getHeight(); - void paint(@NotNull Graphics g, int x, int y, int width, int height, boolean expanded, boolean selected); + void paint(@NotNull Component c, @NotNull Graphics g, int x, int y, int width, int height, boolean expanded, boolean selected); interface Painter { @@ -25,7 +26,7 @@ public interface Control { int getControlOffset(@NotNull Control control, int depth, boolean leaf); - void paint(@NotNull Graphics g, int x, int y, int width, int height, + void paint(@NotNull Component c, @NotNull Graphics g, int x, int y, int width, int height, @NotNull Control control, int depth, boolean leaf, boolean expanded, boolean selected); } } diff --git a/platform/platform-impl/src/com/intellij/ui/tree/ui/DefaultControl.java b/platform/platform-impl/src/com/intellij/ui/tree/ui/DefaultControl.java index e2b767527d87..3696c9bf5a9c 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/ui/DefaultControl.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/ui/DefaultControl.java @@ -4,6 +4,7 @@ package com.intellij.ui.tree.ui; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; +import java.awt.Component; import java.awt.Graphics; import javax.swing.Icon; @@ -36,7 +37,7 @@ public final class DefaultControl implements Control { } @Override - public void paint(@NotNull Graphics g, int x, int y, int width, int height, boolean expanded, boolean selected) { + public void paint(@NotNull Component c, @NotNull Graphics g, int x, int y, int width, int height, boolean expanded, boolean selected) { Icon icon = getIcon(expanded, selected); icon.paintIcon(null, g, x + (width - icon.getIconWidth()) / 2, diff --git a/platform/platform-impl/src/com/intellij/ui/tree/ui/DefaultTreeUI.java b/platform/platform-impl/src/com/intellij/ui/tree/ui/DefaultTreeUI.java index 97f4616d3f1c..1450493d5ed1 100644 --- a/platform/platform-impl/src/com/intellij/ui/tree/ui/DefaultTreeUI.java +++ b/platform/platform-impl/src/com/intellij/ui/tree/ui/DefaultTreeUI.java @@ -210,7 +210,7 @@ public final class DefaultTreeUI extends BasicTreeUI { g.fillRect(viewportX, bounds.y, viewportWidth, bounds.height); } int offset = painter.getRendererOffset(control, depth, leaf); - painter.paint(g, insets.left, bounds.y, offset, bounds.height, control, depth, leaf, expanded, selected && focused); + painter.paint(tree, g, insets.left, bounds.y, offset, bounds.height, control, depth, leaf, expanded, selected && focused); // TODO: editingComponent, editingRow ??? if (editingComponent == null || editingRow != row) { int width = viewportX + viewportWidth - insets.left - offset - vsbWidth; diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index aa611a4a96d2..09f0cd19857f 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -579,7 +579,7 @@ Second Cmd/Ctrl+E switches to Recently Edited Files - + Use popups (instead of dialogs) for creating new items (files, classes, etc.) diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 737f8f913924..7aa798419558 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -612,6 +612,8 @@ + diff --git a/platform/platform-tests/testSrc/com/intellij/execution/process/AnsiEscapeDecoderTest.java b/platform/platform-tests/testSrc/com/intellij/execution/process/AnsiEscapeDecoderTest.java index 759200d6a116..c5faf3b9f375 100644 --- a/platform/platform-tests/testSrc/com/intellij/execution/process/AnsiEscapeDecoderTest.java +++ b/platform/platform-tests/testSrc/com/intellij/execution/process/AnsiEscapeDecoderTest.java @@ -2,6 +2,7 @@ package com.intellij.execution.process; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.testFramework.LightPlatformTestCase; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.util.Consumer; @@ -18,6 +19,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +/** + * important: ansi decoder returns indexed colors set using 30-37, 40-47, 90-97 and 100-107 codes using 38;5;color_number/48;5;color_number + */ public class AnsiEscapeDecoderTest extends LightPlatformTestCase { private static final String STDOUT_KEY = ProcessOutputTypes.STDOUT.toString(); @@ -28,105 +32,162 @@ public class AnsiEscapeDecoderTest extends LightPlatformTestCase { check(new ColoredText("simple text", ProcessOutputTypes.STDOUT).addExpected("simple text", STDOUT_KEY)); } + public void testSequentialSgr() { + check(new ColoredText("This is \u001B[1;3mItalic Bold", ProcessOutputTypes.STDOUT) + .addExpected("This is ", STDOUT_KEY) + .addExpected("Italic Bold", "1;3m") + ); + } + + public void testSequentialSgrOneByOne() { + check(new ColoredText("This is \u001B[1m\u001B[3mItalic Bold", ProcessOutputTypes.STDOUT) + .addExpected("This is ", STDOUT_KEY) + .addExpected("Italic Bold", "1;3m") + ); + } + public void testSingleColoredChunk() { check(new ColoredText("Chrome 35.0.1916 (Linux): Executed 0 of 1\u001B[32m SUCCESS\u001B[39m (0 secs / 0 secs)\n", ProcessOutputTypes.STDOUT) .addExpected("Chrome 35.0.1916 (Linux): Executed 0 of 1", STDOUT_KEY) - .addExpected(" SUCCESS", "\u001B[32m") - .addExpected(" (0 secs / 0 secs)\n", "\u001B[39m")); + .addExpected(" SUCCESS", "38;5;2m") + .addExpected(" (0 secs / 0 secs)\n", STDOUT_KEY)); } public void testCompoundEscSeq() { check(new ColoredText("E\u001B[41m\u001B[37mE\u001B[0mE", ProcessOutputTypes.STDOUT) .addExpected("E", STDOUT_KEY) - .addExpected("E", "\u001B[41;37m") + .addExpected("E", "48;5;1;38;5;7m") .addExpected("E", STDOUT_KEY)); } public void testOtherEscSeq() { check(new ColoredText("Plain\u001B[32mGreen\u001B[39mNormal\u001B[1A\u001B[2K\u001B[31mRed\u001B[39m", ProcessOutputTypes.STDOUT) .addExpected("Plain", STDOUT_KEY) - .addExpected("Green", "\u001B[32m") - .addExpected("Normal", "\u001B[39m") - .addExpected("Red", "\u001B[31m")); + .addExpected("Green", "38;5;2m") + .addExpected("Normal", STDOUT_KEY) + .addExpected("Red", "38;5;1m")); } public void testPrivateSequence() { - check(new ColoredText("\u001B[0;32mgreen\u001B[0m\u001B[0K\u001B[?25l\n", ProcessOutputTypes.STDOUT) - .addExpected("green", "\u001B[0;32m") + check(new ColoredText("\u001B[0m\u001B[32mgreen\u001B[0m\u001B[0K\u001B[?25l\n", ProcessOutputTypes.STDOUT) + .addExpected("green", "38;5;2m") .addExpected("\n", STDOUT_KEY) ); } - public void testMalformedSequence() { + public void testMalformedSequence1() { check(false, Collections.singletonList(new ColoredText("\u001B[32mGreen\u001B[\1World\n", ProcessOutputTypes.STDOUT) - .addExpected("Green\u001B[\1World\n", "\u001B[32m") - )); - check(false, Collections.singletonList(new ColoredText("\u001B\n", ProcessOutputTypes.STDOUT) - .addExpected("\u001B\n", ProcessOutputTypes.STDOUT.toString()) - )); - check(false, Collections.singletonList(new ColoredText("\u001B[\n", ProcessOutputTypes.STDOUT) - .addExpected("\u001B[\n", ProcessOutputTypes.STDOUT.toString()) - )); - check(false, ContainerUtil.newArrayList( - new ColoredText("\u001B\nHello,", ProcessOutputTypes.STDOUT) - .addExpected("\u001B\nHello,", ProcessOutputTypes.STDOUT.toString()), - new ColoredText("\u001B[31mWorld", ProcessOutputTypes.STDOUT) - .addExpected("World", "\u001B[31m") - )); - check(false, ContainerUtil.newArrayList( - new ColoredText("\u001BHello,", ProcessOutputTypes.STDOUT) - .addExpected("\u001BHello,", ProcessOutputTypes.STDOUT.toString()) - )); - check(false, ContainerUtil.newArrayList( - new ColoredText("\u001B[Hello,", ProcessOutputTypes.STDOUT) - .addExpected("ello,", ProcessOutputTypes.STDOUT.toString()) - )); - check(false, ContainerUtil.newArrayList( - new ColoredText("something[\u001B]asdf[\u001B[]", ProcessOutputTypes.STDOUT) - .addExpected("something[\u001B]asdf[\u001B[]", ProcessOutputTypes.STDOUT.toString()) + .addExpected("Green", "38;5;2m") + .addExpected("\u001B[\1World\n", "38;5;2m") )); } - public void testIncompleteEscapeSequences() { + public void testMalformedSequence2() { + check(false, Collections.singletonList(new ColoredText("\u001B\n", ProcessOutputTypes.STDOUT) + .addExpected("\u001B\n", ProcessOutputTypes.STDOUT.toString()) + )); + } + + public void testMalformedSequence3() { + check(false, Collections.singletonList(new ColoredText("\u001B[\n", ProcessOutputTypes.STDOUT) + .addExpected("\u001B[\n", ProcessOutputTypes.STDOUT.toString()) + )); + } + + public void testMalformedSequence4() { + check(false, ContainerUtil.newArrayList( + new ColoredText("\u001B\nHello,", ProcessOutputTypes.STDOUT) + .addExpected("\u001B\nHello,", STDOUT_KEY), + new ColoredText("\u001B[31mWorld", ProcessOutputTypes.STDOUT) + .addExpected("World", "38;5;1m") + )); + } + + public void testMalformedSequence5() { + check(false, ContainerUtil.newArrayList( + new ColoredText("\u001BHello,", ProcessOutputTypes.STDOUT) + .addExpected("\u001BHello,", STDOUT_KEY) + )); + } + + public void testMalformedSequence6() { + check(false, ContainerUtil.newArrayList( + new ColoredText("\u001B[Hello,", ProcessOutputTypes.STDOUT) + .addExpected("ello,", STDOUT_KEY) + )); + } + + public void testMalformedSequence7() { + check(false, ContainerUtil.newArrayList( + new ColoredText("something[\u001B]asdf[\u001B[]", ProcessOutputTypes.STDOUT) + .addExpected("something[", STDOUT_KEY) + .addExpected("\u001B]asdf[", STDOUT_KEY) + )); + } + + public void testIncompleteEscapeSequence1() { check(true, ContainerUtil.newArrayList( new ColoredText("\u001B", ProcessOutputTypes.STDOUT), - new ColoredText("[33m Hello\u001B[3", ProcessOutputTypes.STDOUT).addExpected(" Hello", "\u001B[33m"), - new ColoredText("4m, Work!", ProcessOutputTypes.STDOUT).addExpected(", Work!", "\u001B[34m") + new ColoredText("[33m Hello\u001B[3", ProcessOutputTypes.STDOUT) + .addExpected(" Hello", "38;5;3m"), + new ColoredText("4m, Work!", ProcessOutputTypes.STDOUT) + .addExpected(", Work!", "38;5;4m") )); + } + + public void testIncompleteEscapeSequence2() { check(true, ContainerUtil.newArrayList( - new ColoredText("\u001B[1;33m<\u001B[34mnamespace\u001B[1", ProcessOutputTypes.STDOUT) - .addExpected("<", "\u001B[1;33m") - .addExpected("namespace", "\u001B[34m"), - new ColoredText( - ";33m:abcd\u001B[0m\u001B[1;33m>\u001B[0m0\u001B[1;33m\u001B[0m", - ProcessOutputTypes.STDOUT) - .addExpected(":abcd", "\u001B[1;33m") - .addExpected(">", "\u001B[0;1;33m") - .addExpected("0", "stdout") - .addExpected("", "\u001B[0;1;33m") + new ColoredText("\u001B[1m\u001B[33m<" + + "\u001B[34mnamespace" + + "\u001B[1m", ProcessOutputTypes.STDOUT) + .addExpected("<", "1;38;5;3m") + .addExpected("namespace", "1;38;5;4m"), + new ColoredText("\u001B[33m:abcd" + + "\u001B[0m" + + "\u001B[1;33m>" + + "\u001B[0m0" + + "\u001B[1;33m" + + "\u001B[0m", + ProcessOutputTypes.STDOUT) + .addExpected(":abcd", "1;38;5;3m") + .addExpected(">", "1;38;5;3m") + .addExpected("0", STDOUT_KEY) + .addExpected("", "1;38;5;3m") )); + } + + public void testIncompleteEscapeSequence3() { check(false, ContainerUtil.newArrayList( - new ColoredText("\u001B[1;31m red\u001B[0m normal\u001B[1;32m green\u001B", ProcessOutputTypes.STDOUT) - .addExpected(" red", "\u001B[1;31m") + new ColoredText("\u001B[1m\u001B[31m red" + + "\u001B[0m normal" + + "\u001B[1m\u001B[32m green" + + "\u001B", ProcessOutputTypes.STDOUT) + .addExpected(" red", "1;38;5;1m") .addExpected(" normal", STDOUT_KEY) - .addExpected(" green", "\u001B[1;32m"), - new ColoredText("[0m\n", ProcessOutputTypes.STDOUT).addExpected("\n", STDOUT_KEY) + .addExpected(" green", "1;38;5;2m"), + new ColoredText("[0m\n", ProcessOutputTypes.STDOUT) + .addExpected("\n", STDOUT_KEY) )); } public void testStderr() { check(true, ContainerUtil.newArrayList( - new ColoredText("\u001B[33m Hello,", ProcessOutputTypes.STDOUT).addExpected(" Hello,", "\u001B[33m"), - new ColoredText("World!\n", ProcessOutputTypes.STDERR).addExpected("World!\n", STDERR_KEY), + new ColoredText("\u001B[33m Hello,", ProcessOutputTypes.STDOUT) + .addExpected(" Hello,", "38;5;3m"), + new ColoredText("World!\n", ProcessOutputTypes.STDERR) + .addExpected("World!\n", STDERR_KEY), new ColoredText("\u001B[41m Changed stderr background", ProcessOutputTypes.STDERR) - .addExpected(" Changed stderr background", "\u001B[41m"), + .addExpected(" Changed stderr background", "48;5;1m"), new ColoredText("Unchanged stdout background", ProcessOutputTypes.STDOUT) - .addExpected("Unchanged stdout background", "\u001B[33m") + .addExpected("Unchanged stdout background", "38;5;3m") )); } @@ -137,10 +198,8 @@ public class AnsiEscapeDecoderTest extends LightPlatformTestCase { private static void check(boolean testCharByCharProcessing, @NotNull List texts) { AnsiEscapeDecoder decoder = new AnsiEscapeDecoder(); List> actualColoredChunks = ContainerUtil.newArrayList(); - //noinspection CodeBlock2Expr - AnsiEscapeDecoder.ColoredTextAcceptor acceptor = (text, attributes) -> { - actualColoredChunks.add(Pair.create(text, attributes.toString())); - }; + AnsiEscapeDecoder.ColoredTextAcceptor acceptor = (text, attributes) -> + actualColoredChunks.add(Pair.create(text, StringUtil.trimStart(attributes.toString(), "\u001b[0;"))); for (ColoredText text : texts) { decoder.escapeText(text.myRawText, text.myOutputType, acceptor); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/IterationStateTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/IterationStateTest.java index 7bcbb90ccebb..6eaa1a616411 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/IterationStateTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/IterationStateTest.java @@ -24,10 +24,7 @@ import com.intellij.openapi.editor.impl.view.IterationState; import com.intellij.openapi.editor.markup.HighlighterLayer; import com.intellij.openapi.editor.markup.HighlighterTargetArea; import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.fileTypes.PlainTextFileType; import com.intellij.testFramework.EditorTestUtil; -import com.intellij.testFramework.fixtures.EditorMouseFixture; -import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; import org.junit.Assert; @@ -37,7 +34,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; -public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase { +public class IterationStateTest extends AbstractEditorTest { private Color DEFAULT_BACKGROUND; private Color CARET_ROW_BACKGROUND; private Color SELECTION_BACKGROUND; @@ -159,7 +156,7 @@ public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase init("abc"); getEditor().getColorsScheme().setAttributes(HighlighterColors.TEXT, new TextAttributes(Color.black, Color.white, null, null, Font.BOLD)); - IterationState it = new IterationState(getEditor(), 0, 3, null, false, false, true, false); + IterationState it = new IterationState((EditorEx)getEditor(), 0, 3, null, false, false, true, false); assertFalse(it.atEnd()); assertEquals(0, it.getStartOffset()); assertEquals(3, it.getEndOffset()); @@ -173,7 +170,7 @@ public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase assertNotNull(getEditor().getSoftWrapModel().getSoftWrap(2)); addRangeHighlighter(1, 3, 0, Color.red); addRangeHighlighter(1, 2, 1, Color.blue); - IterationState it = new IterationState(getEditor(), 0, 4, null, false, false, false, false); + IterationState it = new IterationState((EditorEx)getEditor(), 0, 4, null, false, false, false, false); it.advance(); it.advance(); assertFalse(it.atEnd()); @@ -183,19 +180,15 @@ public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase assertEquals(Color.red, it.getBeforeLineStartBackgroundAttributes().getBackgroundColor()); } - private EditorImpl getEditor() { - return (EditorImpl)myFixture.getEditor(); - } - - private void addRangeHighlighter(int startOffset, int endOffset, int layer, Color bgColor) { + private static void addRangeHighlighter(int startOffset, int endOffset, int layer, Color bgColor) { getEditor().getMarkupModel().addRangeHighlighter(startOffset, endOffset, layer, - new TextAttributes(null, bgColor, null, null, 0), + new TextAttributes(null, bgColor, null, null, Font.PLAIN), HighlighterTargetArea.EXACT_RANGE); } - private void verifySplitting(boolean checkForegroundColor, @NotNull Segment... expectedSegments) { - EditorEx editor = getEditor(); + private static void verifySplitting(boolean checkForegroundColor, @NotNull Segment... expectedSegments) { + EditorEx editor = (EditorEx)getEditor(); IterationState.CaretData caretData = IterationState.createCaretData(editor); IterationState iterationState = new IterationState(editor, 0, editor.getDocument().getTextLength(), caretData, false, false, true, false); @@ -214,16 +207,12 @@ public class IterationStateTest extends LightPlatformCodeInsightFixtureTestCase } private void init(String text) { - myFixture.configureByText(PlainTextFileType.INSTANCE, text); + configureFromFileText(getTestName(true) + ".txt", text); EditorTestUtil.setEditorVisibleSize(getEditor(), 1000, 1000); } - private void setColumnModeOn() { - getEditor().setColumnMode(true); - } - - private EditorMouseFixture mouse() { - return new EditorMouseFixture(getEditor()); + private static void setColumnModeOn() { + ((EditorEx)getEditor()).setColumnMode(true); } private static class Segment { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapTest.java index d0447268c4a6..825097dc7c93 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapTest.java @@ -40,6 +40,10 @@ public class SoftWrapTest extends AbstractEditorTest { doTestSoftWraps(10, "foo\nvery long text"); } + public void testNoWrapInsideFoldRegion() { + doTestSoftWraps(10, "starttext with spaceend"); + } + private static final String TAGS_PATTERN = "()|()|"; private void doTestSoftWraps(int wrapWidth, String text) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java index f66cde73f06a..fbbb588ee7cc 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java @@ -78,21 +78,18 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT } } - public void testLongLineOfIdSymbolsIsNotSoftWrapped() { + public void testLongLineOfIdSymbolsIsSoftWrapped() { String text = "abcdefghijklmnopqrstuvwxyz\n" + "123\n" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; init(15, text); - assertTrue(getSoftWrapModel().getRegisteredSoftWraps().isEmpty()); + verifySoftWrapPositions(14, 45); type('1'); - assertTrue(getSoftWrapModel().getRegisteredSoftWraps().isEmpty()); - - int offset = myEditor.getDocument().getText().indexOf("\n"); + verifySoftWrapPositions(14, 46); type(" test"); - assertEquals(1, getSoftWrapModel().getRegisteredSoftWraps().size()); - assertNotNull(getSoftWrapModel().getSoftWrap(offset)); + verifySoftWrapPositions(14, 27, 51); } public void testFoldRegionCollapsing() { @@ -164,23 +161,6 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT assertEquals(new VisualPosition(2, 4), myEditor.getCaretModel().getVisualPosition()); } - public void testTypingThatExceedsRightMarginOnLastSoftWrappedLine() { - String text = - "line1\n" + - "long line"; - - init(69, text, 10); - - int softWrapsBefore = getSoftWrapModel().getRegisteredSoftWraps().size(); - assertTrue(softWrapsBefore > 0); - - for (int i = 0; i < 10; i++) { - type(String.valueOf(i)); - assertEquals(softWrapsBefore, getSoftWrapModel().getRegisteredSoftWraps().size()); - assertEquals(myEditor.getDocument().getTextLength(), myEditor.getCaretModel().getOffset()); - } - } - public void testTrailingFoldRegionRemoval() { String text = "public class BrokenAlignment {\n" + @@ -451,7 +431,7 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT "line4\n" + "line5"; - init(43, text, 10); + init(63, text, 10); int start = text.indexOf("line3") - 1; addCollapsedFoldRegion(start, text.length(), "..."); assertEquals(1, getSoftWrapModel().getRegisteredSoftWraps().size()); @@ -718,7 +698,7 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT "444"; init(15, text); - assertEquals(new LogicalPosition(3, 0), myEditor.visualToLogicalPosition(new VisualPosition(4, 0))); + assertEquals(new LogicalPosition(3, 0), myEditor.visualToLogicalPosition(new VisualPosition(6, 0))); } public void testDeleteThatEndsOnLineWithMultiLineFoldRegion() { @@ -743,7 +723,7 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT assertEquals(new VisualPosition(1, 8), getEditor().offsetToVisualPosition(getEditor().getDocument().getTextLength() - 1)); } - public void testNoWrapAtFirstNonWsSymbolWithCustomIndent() { + public void testWrapAtFirstNonWsSymbolWithCustomIndent() { String text = " 1111111111111111111111111111111"; init(10, text); @@ -752,9 +732,7 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT //Trigger soft wraps recalculation. ((SoftWrapModelImpl)myEditor.getSoftWrapModel()).prepareToMapping(); - // Don't expect soft wraps to be registered as there is no point in wrapping at the first non-white space symbol position - // in all cases when soft wrap is located at the left screen edge. - assertEmpty(getSoftWrapModel().getRegisteredSoftWraps()); + verifySoftWrapPositions(3, 11, 19, 27); } public void testLeadingTabWithShiftedWidth() { @@ -836,7 +814,7 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT } public void testMultiLineFoldRegionBeforeWrapPosition() { - final String text = + final String text = "package org.denis;\n" + "\n" + "\n" + @@ -866,7 +844,7 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT final List wraps = getSoftWrapModel().getRegisteredSoftWraps(); assertEquals(1, wraps.size()); - assertEquals(end, wraps.get(0).getStart()); + assertEquals(start, wraps.get(0).getStart()); assertEquals(myEditor.offsetToVisualPosition(start), myEditor.offsetToVisualPosition(start + 1)); assertEquals(myEditor.offsetToVisualPosition(start).line, myEditor.offsetToVisualPosition(end - 1).line); } @@ -985,9 +963,9 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT } public void testOnlyMinimalRangeIsRecalculatedOnDocumentChange() { - init("aa bb cc dd ee ff gg hh ii jj", TestFileType.TEXT); + init("aa bb cc dd ee ff gg hh ii jj", TestFileType.TEXT); EditorTestUtil.configureSoftWraps(myEditor, 8); - verifySoftWrapPositions(6, 12, 18, 24); + verifySoftWrapPositions(8, 15, 21); final IncrementalCacheUpdateEvent[] event = new IncrementalCacheUpdateEvent[1]; ((SoftWrapModelImpl)myEditor.getSoftWrapModel()).getApplianceManager().addListener(new SoftWrapAwareDocumentParsingListenerAdapter() { @@ -1000,10 +978,10 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT type(' '); - verifySoftWrapPositions(6, 12, 19, 25); + verifySoftWrapPositions(8, 15, 22); assertNotNull(event[0]); - assertEquals(6, event[0].getStartOffset()); - assertEquals(19, event[0].getActualEndOffset()); + assertEquals(8, event[0].getStartOffset()); + assertEquals(22, event[0].getActualEndOffset()); } public void testPositionsAreCorrectAfterIncrementalRecalculation() { @@ -1035,17 +1013,17 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT initText("unbreakableLine\nshort line"); configureSoftWraps(10); - verifySoftWrapPositions(); + verifySoftWrapPositions(10); } public void testFoldRegionPreventsLaterWrapping() { initText("unbreakableText.txt"); configureSoftWraps(10); - verifySoftWrapPositions(15); + verifySoftWrapPositions(10); addCollapsedFoldRegion(12, 13, "."); - verifySoftWrapPositions(12); + verifySoftWrapPositions(10); assertEquals(1, myEditor.offsetToVisualPosition(19).line); } diff --git a/platform/platform-tests/testSrc/com/intellij/ui/tree/ui/TreeControlPainterTest.java b/platform/platform-tests/testSrc/com/intellij/ui/tree/ui/TreeControlPainterTest.java index 64bcc55794a9..c8c927849d70 100644 --- a/platform/platform-tests/testSrc/com/intellij/ui/tree/ui/TreeControlPainterTest.java +++ b/platform/platform-tests/testSrc/com/intellij/ui/tree/ui/TreeControlPainterTest.java @@ -8,6 +8,7 @@ import org.junit.Assert; import org.junit.ClassRule; import org.junit.Test; +import java.awt.Component; import java.awt.Graphics; import javax.swing.Icon; @@ -180,7 +181,7 @@ public class TreeControlPainterTest { } @Override - public void paint(@NotNull Graphics g, int x, int y, int width, int height, boolean expanded, boolean selected) { + public void paint(@NotNull Component c, @NotNull Graphics g, int x, int y, int width, int height, boolean expanded, boolean selected) { } } } diff --git a/platform/platform-tests/testSrc/com/intellij/util/concurrency/BackgroundTaskQueueTest.java b/platform/platform-tests/testSrc/com/intellij/util/concurrency/BackgroundTaskQueueTest.java index 3504ca5a1d5d..598902a90c10 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/concurrency/BackgroundTaskQueueTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/concurrency/BackgroundTaskQueueTest.java @@ -282,7 +282,7 @@ public class BackgroundTaskQueueTest extends PlatformTestCase { private static void waitForTasks(TestTask... tasks) throws InterruptedException { for (TestTask task : tasks) { - task.waitFor(1, TimeUnit.SECONDS); + task.waitFor(1, TimeUnit.MINUTES); } } diff --git a/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java b/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java index a8c89ca98f4f..c5a4e5a47bb6 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java @@ -27,6 +27,7 @@ import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootModificationUtil; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -49,15 +50,13 @@ public class LightProjectDescriptor { public static final String TEST_MODULE_NAME = "light_idea_test_case"; public void setUpProject(@NotNull Project project, @NotNull SetupHandler handler) throws Exception { - WriteAction.run(() -> { - Module module = createMainModule(project); - handler.moduleCreated(module); - VirtualFile sourceRoot = createSourcesRoot(module); - if (sourceRoot != null) { - handler.sourceRootCreated(sourceRoot); - createContentEntry(module, sourceRoot); - } - }); + Module module = createMainModule(project); + handler.moduleCreated(module); + VirtualFile sourceRoot = WriteAction.compute((ThrowableComputable)() -> createSourcesRoot(module)); + if (sourceRoot != null) { + handler.sourceRootCreated(sourceRoot); + createContentEntry(module, sourceRoot); + } } @NotNull diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 9492c2371a53..42dbe57cdf9e 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -1179,7 +1179,8 @@ git.process.ignored=true git.process.ignored.description=Process and highlight Git ignored files. git.update.incoming.outgoing.info=true git.update.incoming.outgoing.info.description=Update branches info that have incoming/outgoing commits in the Branches popup. - +git.merge.conflicts.toolwindow=false +git.merge.conflicts.toolwindow.description=Show dedicated toolwindow for git merge conflicts hg4idea.process.ignored=true hg4idea.process.ignored.description=Process and highlight mercurial ignored files. \ @@ -1190,6 +1191,11 @@ github.action.pullrequest.state.useapi=false github.action.pullrequest.state.useapi.description=If enabled merge/close API actions will be available instead of browser link. \ Reopen toolwindow to apply. +# todo: deliberately left here for now as it's used in an IDE wizard step (before registry extensions are collected) +cidr.cygwin.cmakePermissionsFix=true +cidr.cygwin.cmakePermissionsFix.description=Update permissions for the bin/ folder inside the installed IDE so that the bundled CMake could run + + # via ExternalSystemApiUtil.isInProcessMode # suppress inspection "UnusedProperty" CompDB.system.in.process=true @@ -1706,7 +1712,7 @@ clipboard.history.max.items.description=Maximum number of items in clipboard his clipboard.history.max.memory=10000000 clipboard.history.max.memory.description=Amount of memory (approximate, order-of-magnitude) clipboard history is allowed to take -editor.old.soft.wrap.logic=true +editor.old.soft.wrap.logic=false editor.old.soft.wrap.logic.description=Restores legacy soft wrap placement logic plugins.show.implementation.details=false diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 5408decbb241..0494209ed163 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -15,6 +15,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.IntFunction; @SuppressWarnings("MethodOverridesStaticMethodOfSuperclass") public class ContainerUtil extends ContainerUtilRt { @@ -555,6 +556,27 @@ public class ContainerUtil extends ContainerUtilRt { return elements.size() > i ? elements.get(i) : defaultValue; } + @NotNull + @Contract(pure=true) + public static Iterator mapIterator(@NotNull TIntIterator iterator, @NotNull IntFunction mapper) { + return new Iterator() { + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public U next() { + return mapper.apply(iterator.next()); + } + + @Override + public void remove() { + iterator.remove(); + } + }; + } + public static class ImmutableMapBuilder { private final Map myMap = new THashMap<>(); diff --git a/platform/util/src/com/intellij/util/containers/FilteredTraverserBase.java b/platform/util/src/com/intellij/util/containers/FilteredTraverserBase.java index 8ed59e2ff484..63b4015f5009 100644 --- a/platform/util/src/com/intellij/util/containers/FilteredTraverserBase.java +++ b/platform/util/src/com/intellij/util/containers/FilteredTraverserBase.java @@ -119,8 +119,13 @@ public abstract class FilteredTraverserBase roots) { - return newInstance(myMeta.withRoots(roots)); + public final Self withRoots(@Nullable T... roots) { + return newInstance(myMeta.withRoots(JBIterable.of(roots))); + } + + @NotNull + public final Self withRoots(@Nullable Iterable roots) { + return newInstance(myMeta.withRoots(roots != null ? roots : JBIterable.empty())); } @NotNull diff --git a/platform/util/src/com/intellij/util/io/IOUtil.java b/platform/util/src/com/intellij/util/io/IOUtil.java index ae45f9cce1c2..731002dcf52c 100644 --- a/platform/util/src/com/intellij/util/io/IOUtil.java +++ b/platform/util/src/com/intellij/util/io/IOUtil.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.Nullable; import java.io.*; import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -119,14 +120,6 @@ public class IOUtil { } } - private static final ThreadLocalCachedValue spareBufferLocal = new ThreadLocalCachedValue() { - @NotNull - @Override - protected char[] create() { - return new char[STRING_LENGTH_THRESHOLD]; - } - }; - public static String readUTFFast(@NotNull byte[] buffer, @NotNull DataInput storage) throws IOException { int len = 0xFF & (int)storage.readByte(); if (len == 0xFF) { @@ -141,9 +134,7 @@ public class IOUtil { if (len == 0) return ""; storage.readFully(buffer, 0, len); - char[] chars = spareBufferLocal.getValue(); - for (int i = 0; i < len; ++i) chars[i] = (char)(buffer[i] & 0xFF); - return new String(chars, 0, len); + return new String(buffer, 0, len, StandardCharsets.ISO_8859_1); } public static boolean isAscii(@NotNull String str) { diff --git a/platform/util/src/com/intellij/util/ui/JBUI.java b/platform/util/src/com/intellij/util/ui/JBUI.java index 3a8aed5bacb6..8f4fae34320a 100644 --- a/platform/util/src/com/intellij/util/ui/JBUI.java +++ b/platform/util/src/com/intellij/util/ui/JBUI.java @@ -1139,6 +1139,31 @@ public class JBUI { : UIUtil.getPanelBackground(); } } + + public static class NewClassDialog { + @NotNull + public static Color searchFieldBackground() { + return JBColor.namedColor("NewClass.SearchField.background", 0xffffff); + } + + @NotNull + public static Color panelBackground() { + return JBColor.namedColor("NewClass.Panel.background", 0xf2f2f2); + } + + @NotNull + public static Color bordersColor() { + return JBColor.namedColor( + "TextField.borderColor", + JBColor.namedColor("Component.borderColor", new JBColor(0xbdbdbd, 0x646464)) + ); + } + + @NotNull + public static int fieldsSeparatorWidth() { + return getInt("NewClass.separatorWidth", JBUI.scale(10)); + } + } } diff --git a/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java b/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java index dad1ad6a7406..1ae1607ef0a3 100644 --- a/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java +++ b/platform/vcs-api/src/com/intellij/vcsUtil/VcsUtil.java @@ -23,7 +23,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Ref; @@ -37,6 +39,7 @@ import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.*; import com.intellij.openapi.wm.StatusBar; import com.intellij.util.Function; +import com.intellij.util.ThrowableConvertor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -416,6 +419,19 @@ public class VcsUtil { return result; } + public static T computeWithModalProgress(@Nullable Project project, + @NotNull String title, + boolean canBeCancelled, + @NotNull ThrowableConvertor computable) + throws VcsException { + return ProgressManager.getInstance().run(new Task.WithResult(project, title, canBeCancelled) { + @Override + protected T compute(@NotNull ProgressIndicator indicator) throws VcsException { + return computable.convert(indicator); + } + }); + } + @Deprecated @Nullable public static VirtualFile waitForTheFile(@NotNull String path) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ZipAndQueue.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ZipAndQueue.java index 745ea954c999..1c276fd91873 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ZipAndQueue.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ZipAndQueue.java @@ -21,7 +21,6 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.SomeQueue; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.ZipperUpdater; import org.jetbrains.annotations.NotNull; @@ -35,9 +34,13 @@ public class ZipAndQueue { private final Runnable myInZipper; private Task.Backgroundable myInvokedOnQueue; - public ZipAndQueue(@NotNull Project project, final int interval, final String title, final Runnable runnable) { + public ZipAndQueue(@NotNull Project project, + final int interval, + final String title, + @NotNull Disposable parentDisposable, + final Runnable runnable) { final int correctedInterval = interval <= 0 ? 300 : interval; - myZipperUpdater = new ZipperUpdater(correctedInterval, project); + myZipperUpdater = new ZipperUpdater(correctedInterval, parentDisposable); myQueue = new BackgroundTaskQueue(project, title); myInZipper = () -> myQueue.run(myInvokedOnQueue); myInvokedOnQueue = new Task.Backgroundable(project, title, false) { @@ -46,19 +49,9 @@ public class ZipAndQueue { runnable.run(); } }; - Disposer.register(project, new Disposable() { - @Override - public void dispose() { - myZipperUpdater.stop(); - } - }); } public void request() { myZipperUpdater.queue(myInZipper); } - - public void stop() { - myZipperUpdater.stop(); - } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/DefaultPatchBaseVersionProvider.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/DefaultPatchBaseVersionProvider.java index d16fceded8e0..20d85ec519d2 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/DefaultPatchBaseVersionProvider.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/DefaultPatchBaseVersionProvider.java @@ -19,11 +19,7 @@ package com.intellij.openapi.vcs.changes.patch; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.impl.LoadTextUtil; import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.ProjectLevelVcsManager; @@ -33,10 +29,8 @@ import com.intellij.openapi.vcs.diff.DiffProvider; import com.intellij.openapi.vcs.history.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Processor; +import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.CalledInAny; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.Date; @@ -89,8 +83,8 @@ public class DefaultPatchBaseVersionProvider { final VcsRevisionNumber finalRevision = revision; try { if (finalRevision != null) { - final boolean loadedExactRevision = - computeInBackgroundTask(myProject, message("progress.text2.loading.revision", finalRevision.asString()), true, () -> { + String message = message("progress.text2.loading.revision", finalRevision.asString()); + boolean loadedExactRevision = VcsUtil.computeWithModalProgress(myProject, message, true, indicator -> { if (historyProvider instanceof VcsBaseRevisionAdviser) { VcsBaseRevisionAdviser revisionAdviser = (VcsBaseRevisionAdviser)historyProvider; return revisionAdviser.getBaseVersionContent(filePath, processor, finalRevision.asString()); @@ -131,8 +125,8 @@ public class DefaultPatchBaseVersionProvider { final VcsHistorySession historySession; try { - historySession = computeInBackgroundTask(myProject, message("loading.file.history.progress"), true, - () -> historyProvider.createSessionFor(filePath)); + historySession = VcsUtil.computeWithModalProgress(myProject, message("loading.file.history.progress"), true, + indicator -> historyProvider.createSessionFor(filePath)); } catch (ProcessCanceledException e) { return; @@ -203,16 +197,4 @@ public class DefaultPatchBaseVersionProvider { } return null; } - - public static T computeInBackgroundTask(@Nullable Project project, - @Nls(capitalization = Nls.Capitalization.Title) @NotNull String title, - boolean canBeCancelled, - @NotNull ThrowableComputable computable) throws E { - return ProgressManager.getInstance().run(new Task.WithResult(project, title, canBeCancelled) { - @Override - protected T compute(@NotNull ProgressIndicator indicator) throws E { - return computable.compute(); - } - }); - } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchDiffRequestFactory.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchDiffRequestFactory.java index 676d2f8d7d06..6055402570aa 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchDiffRequestFactory.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/PatchDiffRequestFactory.java @@ -20,6 +20,7 @@ import com.intellij.diff.DiffRequestFactory; import com.intellij.diff.InvalidDiffRequestException; import com.intellij.diff.chains.DiffRequestProducerException; import com.intellij.diff.contents.DocumentContent; +import com.intellij.diff.merge.MergeCallback; import com.intellij.diff.merge.MergeRequest; import com.intellij.diff.merge.MergeResult; import com.intellij.diff.requests.DiffRequest; @@ -209,8 +210,9 @@ public class PatchDiffRequestFactory { if (patchTitle == null) patchTitle = VcsBundle.message("patch.apply.conflict.patch"); DocumentContent resultContent = DiffContentFactory.getInstance().create(project, document, file); - return new ApplyPatchMergeRequest(project, resultContent, textPatch, localContent, - windowTitle, localTitle, resultTitle, patchTitle, callback); + ApplyPatchMergeRequest request = new ApplyPatchMergeRequest(project, resultContent, textPatch, localContent, + windowTitle, localTitle, resultTitle, patchTitle); + return MergeCallback.register(request, callback); } @NotNull diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeRequest.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeRequest.java index 67bd6b70ab04..9c5f37ad206e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeRequest.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/tool/ApplyPatchMergeRequest.java @@ -16,13 +16,14 @@ package com.intellij.openapi.vcs.changes.patch.tool; import com.intellij.diff.contents.DocumentContent; +import com.intellij.diff.merge.MergeCallback; import com.intellij.diff.merge.MergeRequest; import com.intellij.diff.merge.MergeResult; +import com.intellij.diff.merge.MergeUtil; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.changes.patch.AppliedTextPatch; -import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,8 +41,6 @@ public class ApplyPatchMergeRequest extends MergeRequest implements ApplyPatchRe @NotNull private final String myResultTitle; @NotNull private final String myPatchTitle; - @Nullable private final Consumer myCallback; - public ApplyPatchMergeRequest(@Nullable Project project, @NotNull DocumentContent resultContent, @NotNull AppliedTextPatch appliedPatch, @@ -49,8 +48,7 @@ public class ApplyPatchMergeRequest extends MergeRequest implements ApplyPatchRe @Nullable String windowTitle, @NotNull String localTitle, @NotNull String resultTitle, - @NotNull String patchTitle, - @Nullable Consumer callback) { + @NotNull String patchTitle) { myProject = project; myResultContent = resultContent; myAppliedPatch = appliedPatch; @@ -62,8 +60,6 @@ public class ApplyPatchMergeRequest extends MergeRequest implements ApplyPatchRe myLocalTitle = localTitle; myResultTitle = resultTitle; myPatchTitle = patchTitle; - - myCallback = callback; } @Nullable @@ -118,7 +114,7 @@ public class ApplyPatchMergeRequest extends MergeRequest implements ApplyPatchRe final CharSequence applyContent; switch (result) { case CANCEL: - applyContent = myOriginalContent; + applyContent = MergeUtil.shouldRestoreOriginalContentOnCancel(this) ? myOriginalContent : null; break; case LEFT: applyContent = myLocalContent; @@ -136,6 +132,6 @@ public class ApplyPatchMergeRequest extends MergeRequest implements ApplyPatchRe WriteCommandAction.writeCommandAction(myProject).run(() -> myResultContent.getDocument().setText(applyContent)); } - if (myCallback != null) myCallback.consume(result); + MergeCallback.getCallback(this).applyResult(result); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNodeRenderer.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNodeRenderer.java index 7c546828d098..f32e54872772 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNodeRenderer.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNodeRenderer.java @@ -49,7 +49,7 @@ public class ChangesBrowserNodeRenderer extends ColoredTreeCellRenderer { SpeedSearchUtil.applySpeedSearchHighlighting(tree, this, true, selected); } - protected void appendFileName(@Nullable VirtualFile vFile, @NotNull String fileName, Color color) { + public void appendFileName(@Nullable VirtualFile vFile, @NotNull String fileName, Color color) { ChangesFileNameDecorator decorator = myProject != null && !myProject.isDefault() ? ChangesFileNameDecorator.getInstance(myProject) : null; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java index 95dbd4e1f0a9..a764afe10c11 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesViewContentManager.java @@ -22,7 +22,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import java.util.concurrent.CountDownLatch; public class ChangesViewContentManager implements ChangesViewContentI { @@ -65,9 +67,8 @@ public class ChangesViewContentManager implements ChangesViewContentI { loadExtensionTabs(); myContentManager = contentManager; - final List ordered = doPresetOrdering(myAddedContents); - for(Content content: ordered) { - myContentManager.addContent(content); + for (Content content : myAddedContents) { + addIntoCorrectPlace(content); } myAddedContents.clear(); if (contentManager.getContentCount() > 0) { @@ -257,54 +258,66 @@ public class ChangesViewContentManager implements ChangesViewContentI { } } + public static final Key ORDER_WEIGHT_KEY = Key.create("ChangesView.ContentOrderWeight"); public static final String LOCAL_CHANGES = "Local Changes"; public static final String REPOSITORY = "Repository"; public static final String INCOMING = "Incoming"; public static final String SHELF = "Shelf"; - private static final String[] ourPresetOrder = {LOCAL_CHANGES, REPOSITORY, INCOMING, SHELF}; - private static List doPresetOrdering(final List contents) { - final List result = new ArrayList<>(contents.size()); - for (final String preset : ourPresetOrder) { - for (Iterator iterator = contents.iterator(); iterator.hasNext();) { - final Content current = iterator.next(); - if (preset.equals(current.getTabName())) { - iterator.remove(); - result.add(current); - } - } + + public enum TabOrderWeight { + LOCAL_CHANGES(ChangesViewContentManager.LOCAL_CHANGES, 10), + REPOSITORY(ChangesViewContentManager.REPOSITORY, 20), + INCOMING(ChangesViewContentManager.INCOMING, 30), + SHELF(ChangesViewContentManager.SHELF, 40), + OTHER(null, 100); + + @Nullable private final String myName; + private final int myWeight; + + TabOrderWeight(@Nullable String name, int weight) { + myName = name; + myWeight = weight; + } + + @Nullable + private String getName() { + return myName; + } + + public int getWeight() { + return myWeight; } - result.addAll(contents); - return result; } private void addIntoCorrectPlace(final Content content) { - final String name = content.getTabName(); + int weight = getContentWeight(content); + final Content[] contents = myContentManager.getContents(); - int idxOfBeingInserted = -1; - for (int i = 0; i < ourPresetOrder.length; i++) { - final String s = ourPresetOrder[i]; - if (s.equals(name)) { - idxOfBeingInserted = i; + int index = -1; + for (int i = 0; i < contents.length; i++) { + int oldWeight = getContentWeight(contents[i]); + if (oldWeight > weight) { + index = i; + break; } } - if (idxOfBeingInserted == -1) { - myContentManager.addContent(content); - return; - } - final Set existingNames = new HashSet<>(); - for (Content existingContent : contents) { - existingNames.add(existingContent.getTabName()); - } + if (index == -1) index = contents.length; + myContentManager.addContent(content, index); + } - int place = idxOfBeingInserted; - for (int i = 0; i < idxOfBeingInserted; i++) { - if (! existingNames.contains(ourPresetOrder[i])) { - -- place; + private static int getContentWeight(Content content) { + Integer userData = content.getUserData(ORDER_WEIGHT_KEY); + if (userData != null) return userData; + + String tabName = content.getTabName(); + for (TabOrderWeight value : TabOrderWeight.values()) { + if (value.getName() != null && value.getName().equals(tabName)) { + return value.getWeight(); } - } - myContentManager.addContent(content, place); + + return TabOrderWeight.OTHER.getWeight(); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/merge/MergeConflictsTreeTable.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/merge/MergeConflictsTreeTable.kt new file mode 100644 index 000000000000..d57d463a89e1 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/merge/MergeConflictsTreeTable.kt @@ -0,0 +1,48 @@ +// Copyright 2000-2019 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. +package com.intellij.openapi.vcs.merge + +import com.intellij.openapi.util.text.StringUtil +import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns +import com.intellij.ui.treeStructure.treetable.TreeTable +import com.intellij.util.ui.ColumnInfo +import com.intellij.util.ui.JBUI + +class MergeConflictsTreeTable(private val tableModel: ListTreeTableModelOnColumns) : TreeTable(tableModel) { + init { + getTableHeader().reorderingAllowed = false + tree.isRootVisible = false + if (tableModel.columnCount > 1) setShowColumns(true) + } + + override fun doLayout() { + if (getTableHeader().resizingColumn == null) { + updateColumnSizes() + } + super.doLayout() + } + + private fun updateColumnSizes() { + for ((index, columnInfo) in tableModel.columns.withIndex()) { + val column = columnModel.getColumn(index) + columnInfo.maxStringValue?.let { + val width = calcColumnWidth(it, columnInfo) + column.preferredWidth = width + } + } + + var size = width + val fileColumn = 0 + for (i in 0 until tableModel.columns.size) { + if (i == fileColumn) continue + size -= columnModel.getColumn(i).preferredWidth + } + + columnModel.getColumn(fileColumn).preferredWidth = Math.max(size, JBUI.scale(200)) + } + + private fun calcColumnWidth(maxStringValue: String, columnInfo: ColumnInfo): Int { + val columnName = StringUtil.shortenTextWithEllipsis(columnInfo.name, 15, 7, true) + return Math.max(getFontMetrics(font).stringWidth(maxStringValue), + getFontMetrics(tableHeader.font).stringWidth(columnName)) + columnInfo.additionalWidth + } +} \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/merge/MultipleFileMergeDialog.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/merge/MultipleFileMergeDialog.kt index 28f801ac1395..56956d3f15b4 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/merge/MultipleFileMergeDialog.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/merge/MultipleFileMergeDialog.kt @@ -12,13 +12,11 @@ import com.intellij.diff.merge.MergeUtil import com.intellij.diff.util.DiffUtil import com.intellij.openapi.command.WriteCommandAction.writeCommandAction import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.diff.impl.mergeTool.MergeVersion import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.project.Project import com.intellij.openapi.ui.DialogWrapper import com.intellij.openapi.ui.Messages import com.intellij.openapi.util.io.FileTooBigException -import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vcs.VcsBundle import com.intellij.openapi.vcs.VcsConfiguration import com.intellij.openapi.vcs.VcsException @@ -37,7 +35,6 @@ import com.intellij.ui.treeStructure.treetable.TreeTable import com.intellij.ui.treeStructure.treetable.TreeTableModel import com.intellij.util.containers.Convertor import com.intellij.util.ui.ColumnInfo -import com.intellij.util.ui.JBUI import com.intellij.util.ui.UIUtil import com.intellij.util.ui.tree.TreeUtil import org.jetbrains.annotations.NonNls @@ -125,13 +122,9 @@ open class MultipleFileMergeDialog( } row { - scrollPane(MyTable(tableModel).also { + scrollPane(MergeConflictsTreeTable(tableModel).also { table = it - it.tree.isRootVisible = false it.setTreeCellRenderer(virtualFileRenderer) - if (tableModel.columnCount > 1) { - it.setShowColumns(true) - } it.rowHeight = virtualFileRenderer.preferredSize.height }, growX, growY, pushX, pushY) @@ -195,45 +188,6 @@ open class MultipleFileMergeDialog( override fun getTooltipText() = base.tooltipText ?: columnName } - private class MyTable(private val tableModel: ListTreeTableModelOnColumns) : TreeTable(tableModel) { - - init { - getTableHeader().reorderingAllowed = false - } - - override fun doLayout() { - if (getTableHeader().resizingColumn == null) { - updateColumnSizes() - } - super.doLayout() - } - - private fun updateColumnSizes() { - for ((index, columnInfo) in tableModel.columns.withIndex()) { - val column = columnModel.getColumn(index) - columnInfo.maxStringValue?.let { - val width = calcColumnWidth(it, columnInfo) - column.preferredWidth = width - } - } - - var size = width - val fileColumn = 0 - for (i in 0 until tableModel.columns.size) { - if (i == fileColumn) continue - size -= columnModel.getColumn(i).preferredWidth - } - - columnModel.getColumn(fileColumn).preferredWidth = Math.max(size, JBUI.scale(200)) - } - - private fun calcColumnWidth(maxStringValue: String, columnInfo: ColumnInfo): Int { - val columnName = StringUtil.shortenTextWithEllipsis(columnInfo.name, 15, 7, true) - return Math.max(getFontMetrics(font).stringWidth(maxStringValue), - getFontMetrics(tableHeader.font).stringWidth(columnName)) + columnInfo.additionalWidth - } - } - private fun toggleGroupByDirectory(state: Boolean) { groupByDirectory = state val firstSelectedFile = getSelectedFiles().firstOrNull() @@ -456,7 +410,7 @@ open class MultipleFileMergeDialog( } private fun checkMarkModifiedProject(file: VirtualFile) { - MergeVersion.MergeDocumentVersion.reportProjectFileChangeIfNeeded(project, file) + MergeUtil.reportProjectFileChangeIfNeeded(project, file) } override fun getPreferredFocusedComponent(): JComponent? = table diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualsCharSequenceInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualsCharSequenceInspection.java index c4e3603b56af..f2e8ae50d7ab 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualsCharSequenceInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualsCharSequenceInspection.java @@ -1,18 +1,4 @@ -/* - * 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-2019 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. package com.siyeh.ig.bugs; import com.intellij.codeInspection.ProblemDescriptor; @@ -97,7 +83,8 @@ public class StringEqualsCharSequenceInspection extends BaseInspection { if (!leftType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { return; } - if (rightType.equalsToText(CommonClassNames.JAVA_LANG_STRING) || !InheritanceUtil.isInheritor(rightType, "java.lang.CharSequence")) { + if (rightType.equalsToText(CommonClassNames.JAVA_LANG_STRING) || + !InheritanceUtil.isInheritor(rightType, CommonClassNames.JAVA_LANG_CHARSEQUENCE)) { return; } final PsiElement name = expression.getReferenceNameElement(); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java index ec93f85b7e5d..a97106a51af4 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java @@ -33,6 +33,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +import static com.intellij.psi.CommonClassNames.JAVA_LANG_CHARSEQUENCE; import static com.intellij.util.ObjectUtils.tryCast; /** @@ -329,7 +330,7 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { final PsiExpression argument = arguments[0]; final PsiType type = argument.getType(); if (!PsiType.INT.equals(type)) { - if (type != null && type.equalsToText("java.lang.CharSequence")) { + if (type != null && type.equalsToText(JAVA_LANG_CHARSEQUENCE)) { result.append("String.valueOf(").append(tracker.textWithComments(argument)).append(')'); } else { diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/application/CvsEntriesManager.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/application/CvsEntriesManager.java index 141b02cf8055..6900a790d800 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/application/CvsEntriesManager.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/application/CvsEntriesManager.java @@ -24,6 +24,7 @@ import com.intellij.cvsSupport2.cvsIgnore.IgnoredFilesInfo; import com.intellij.cvsSupport2.cvsIgnore.UserDirIgnores; import com.intellij.cvsSupport2.cvsstatuses.CvsEntriesListener; import com.intellij.cvsSupport2.util.CvsVfsUtil; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; @@ -63,7 +64,6 @@ public class CvsEntriesManager implements VirtualFileListener { private final Map myStringToSettingsMap = new THashMap<>(); private final UserDirIgnores myUserDirIgnores = new UserDirIgnores(); - private final MyVirtualFileManagerListener myVirtualFileManagerListener = new MyVirtualFileManagerListener(); private final CvsApplicationLevelConfiguration myApplicationLevelConfiguration; public static CvsEntriesManager getInstance() { @@ -85,10 +85,10 @@ public class CvsEntriesManager implements VirtualFileListener { } } - public void registerAsVirtualFileListener() { + public void registerAsVirtualFileListener(@NotNull Disposable listenerDisposable) { if (myIsActive == 0) { - VirtualFileManager.getInstance().addVirtualFileListener(this); - VirtualFileManager.getInstance().addVirtualFileManagerListener(myVirtualFileManagerListener); + VirtualFileManager.getInstance().addVirtualFileListener(this, listenerDisposable); + VirtualFileManager.getInstance().addVirtualFileManagerListener(new MyVirtualFileManagerListener(), listenerDisposable); } myIsActive++; } @@ -97,8 +97,6 @@ public class CvsEntriesManager implements VirtualFileListener { LOG.assertTrue(isActive()); myIsActive--; if (myIsActive == 0) { - VirtualFileManager.getInstance().removeVirtualFileListener(this); - VirtualFileManager.getInstance().removeVirtualFileManagerListener(myVirtualFileManagerListener); myInfoByParentDirectoryPath.clear(); } } diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/application/CvsStorageSupportingDeletionComponent.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/application/CvsStorageSupportingDeletionComponent.java index a01ae14aa326..0b7a8aa33686 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/application/CvsStorageSupportingDeletionComponent.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/application/CvsStorageSupportingDeletionComponent.java @@ -46,7 +46,7 @@ public class CvsStorageSupportingDeletionComponent implements VirtualFileListene myProject = project; initializeDeletedStorage(); VirtualFileManager.getInstance().addVirtualFileListener(this, myListenerDisposable); - CvsEntriesManager.getInstance().registerAsVirtualFileListener(); + CvsEntriesManager.getInstance().registerAsVirtualFileListener(myListenerDisposable); project.getMessageBus().connect(myListenerDisposable).subscribe(CommandListener.TOPIC, new CommandListener() { @Override public void commandStarted(@NotNull CommandEvent event) { diff --git a/plugins/git4idea/resources/META-INF/plugin.xml b/plugins/git4idea/resources/META-INF/plugin.xml index 5fbd28114ac8..ce1d3846637d 100644 --- a/plugins/git4idea/resources/META-INF/plugin.xml +++ b/plugins/git4idea/resources/META-INF/plugin.xml @@ -256,6 +256,7 @@ + + + + + git4idea.conflicts.GitConflictsToolWindowManager + + diff --git a/plugins/git4idea/src/git4idea/conflicts/GitConflictsToolWindowManager.java b/plugins/git4idea/src/git4idea/conflicts/GitConflictsToolWindowManager.java new file mode 100644 index 000000000000..f9906790032f --- /dev/null +++ b/plugins/git4idea/src/git4idea/conflicts/GitConflictsToolWindowManager.java @@ -0,0 +1,69 @@ +// Copyright 2000-2019 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. +package git4idea.conflicts; + +import com.intellij.openapi.components.ProjectComponent; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vcs.changes.ui.ChangesViewContentI; +import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager; +import com.intellij.ui.content.Content; +import com.intellij.ui.content.ContentFactory; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.update.MergingUpdateQueue; +import com.intellij.util.ui.update.Update; +import git4idea.repo.GitConflictsHolder; +import git4idea.repo.GitRepository; +import git4idea.repo.GitRepositoryManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class GitConflictsToolWindowManager implements ProjectComponent { + public static final String TAB_NAME = "Conflicts"; + + @NotNull private final Project myProject; + @NotNull private final ChangesViewContentI myContentManager; + @NotNull private final GitRepositoryManager myRepositoryManager; + + private final MergingUpdateQueue myQueue; + + @Nullable private Content myContent; + + public GitConflictsToolWindowManager(@NotNull Project project, + @NotNull ChangesViewContentI contentManager, + @NotNull GitRepositoryManager repositoryManager) { + myProject = project; + myContentManager = contentManager; + myRepositoryManager = repositoryManager; + + myQueue = new MergingUpdateQueue("GitConflictsToolWindowManager", 300, true, null, myProject); + + project.getMessageBus().connect().subscribe(GitConflictsHolder.CONFLICTS_CHANGE, new GitConflictsHolder.ConflictsListener() { + @Override + public void conflictsChanged(@NotNull GitRepository repository) { + myQueue.queue(Update.create("update", () -> updateToolWindow())); + } + }); + } + + private void updateToolWindow() { + if (!Registry.is("git.merge.conflicts.toolwindow")) return; + + boolean hasConflicts = ContainerUtil.exists(myRepositoryManager.getRepositories(), + repo -> !repo.getConflictsHolder().getConflicts().isEmpty()); + if (hasConflicts && myContent == null) { + GitConflictsView panel = new GitConflictsView(myProject); + myContent = ContentFactory.SERVICE.getInstance().createContent(panel.getComponent(), TAB_NAME, false); + myContent.putUserData(ChangesViewContentManager.ORDER_WEIGHT_KEY, + ChangesViewContentManager.TabOrderWeight.REPOSITORY.getWeight() + 1); + myContent.setCloseable(false); + myContent.setPreferredFocusedComponent(() -> panel.getPreferredFocusableComponent()); + Disposer.register(myContent, panel); + myContentManager.addContent(myContent); + } + if (!hasConflicts && myContent != null) { + myContentManager.removeContent(myContent); + myContent = null; + } + } +} diff --git a/plugins/git4idea/src/git4idea/conflicts/GitConflictsView.kt b/plugins/git4idea/src/git4idea/conflicts/GitConflictsView.kt new file mode 100644 index 000000000000..cff4a301cb82 --- /dev/null +++ b/plugins/git4idea/src/git4idea/conflicts/GitConflictsView.kt @@ -0,0 +1,270 @@ +// Copyright 2000-2019 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. +package git4idea.conflicts + +import com.intellij.icons.AllIcons +import com.intellij.openapi.Disposable +import com.intellij.openapi.actionSystem.* +import com.intellij.openapi.application.runInEdt +import com.intellij.openapi.progress.runBackgroundableTask +import com.intellij.openapi.project.DumbAwareAction +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.SimpleToolWindowPanel +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.vcs.FileStatus +import com.intellij.openapi.vcs.changes.ChangesUtil +import com.intellij.openapi.vcs.changes.ui.* +import com.intellij.openapi.vcs.changes.ui.ChangesTree.DEFAULT_GROUPING_KEYS +import com.intellij.openapi.vcs.merge.MergeConflictsTreeTable +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.ui.DoubleClickListener +import com.intellij.ui.ScrollPaneFactory +import com.intellij.ui.TableSpeedSearch +import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns +import com.intellij.ui.treeStructure.treetable.TreeTableModel +import com.intellij.util.Alarm +import com.intellij.util.containers.Convertor +import com.intellij.util.ui.ColumnInfo +import com.intellij.util.ui.UIUtil +import com.intellij.util.ui.tree.TreeUtil +import com.intellij.util.ui.update.MergingUpdateQueue +import com.intellij.util.ui.update.Update +import git4idea.GitUtil +import git4idea.merge.GitMergeUtil +import git4idea.repo.GitConflict +import git4idea.repo.GitConflict.ConflictSide +import git4idea.repo.GitConflictsHolder +import git4idea.repo.GitRepository +import git4idea.repo.GitRepositoryChangeListener +import java.awt.BorderLayout +import java.awt.event.MouseEvent +import java.beans.PropertyChangeListener +import javax.swing.JComponent +import javax.swing.JPanel +import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.TreeNode + +class GitConflictsView(private val project: Project) : Disposable { + private val mergeHandler: GitMergeHandler = GitMergeHandler(project) + + private val panel: SimpleToolWindowPanel + private val table: MergeConflictsTreeTable + private val tableModel: ListTreeTableModelOnColumns + + private val conflicts: MutableList = ArrayList() + private val reversedRoots: MutableSet = HashSet() + + private val updateQueue: MergingUpdateQueue + private val groupingSupport: ChangesGroupingSupport = ChangesGroupingSupport(project, this, false) + + init { + tableModel = ListTreeTableModelOnColumns(DefaultMutableTreeNode(), arrayOf(PathColumn(), YoursColumn(), TheirsColumn())) + table = MergeConflictsTreeTable(tableModel) + updateQueue = MergingUpdateQueue("GitConflictsView", 300, true, table, this, null, Alarm.ThreadToUse.POOLED_THREAD) + + val renderer = ChangesBrowserNodeRenderer(project, { !groupingSupport.isDirectory }, false) + renderer.font = UIUtil.getListFont() + table.setTreeCellRenderer(renderer) + table.rowHeight = renderer.preferredSize.height + + groupingSupport.addPropertyChangeListener(PropertyChangeListener { rebuildTree() }) + groupingSupport.setGroupingKeysOrSkip(DEFAULT_GROUPING_KEYS.toSet()) + + TableSpeedSearch(table, Convertor { (it as? GitConflict)?.filePath?.name }) + + + val actionManager = ActionManager.getInstance() + val toolbarGroup = DefaultActionGroup() + toolbarGroup.addAction(actionManager.getAction("ChangesView.Refresh")) + toolbarGroup.addAction(ResolveAction()) + toolbarGroup.addAction(AcceptSideAction(false)) + toolbarGroup.addAction(AcceptSideAction(true)) + toolbarGroup.addAction(actionManager.getAction(ChangesTree.GROUP_BY_ACTION_GROUP)) + val toolbar = actionManager.createActionToolbar("GitConflictsView", toolbarGroup, false) + toolbar.setTargetComponent(table) + + val mainPanel = MainPanel() + mainPanel.add(ScrollPaneFactory.createScrollPane(table), BorderLayout.CENTER) + + panel = SimpleToolWindowPanel(false, true) + panel.toolbar = toolbar.component + panel.setContent(mainPanel) + + + object : DoubleClickListener() { + override fun onDoubleClick(event: MouseEvent): Boolean { + showMergeWindowForSelection() + return true + } + }.installOn(table) + + val connection = project.messageBus.connect(this) + connection.subscribe(GitConflictsHolder.CONFLICTS_CHANGE, GitConflictsHolder.ConflictsListener { updateConflicts() }) + connection.subscribe(GitRepository.GIT_REPO_CHANGE, GitRepositoryChangeListener { updateConflicts() }) + + updateConflicts() + } + + val component: JComponent? get() = panel + val preferredFocusableComponent: JComponent? get() = table + + override fun dispose() { + } + + private fun getSelectedConflicts(): List { + return TreeUtil.collectSelectedObjectsOfType(table.tree, GitConflict::class.java) + } + + private fun updateConflicts() { + updateQueue.queue(Update.create("update") { + val newConflicts = ArrayList() + val newReversedRoots = ArrayList() + + val repos = GitUtil.getRepositories(project) + for (repo in repos) { + if (GitMergeUtil.isReverseRoot(repo)) newReversedRoots.add(repo.root) + newConflicts.addAll(repo.conflictsHolder.conflicts) + } + + runInEdt { + conflicts.clear() + conflicts.addAll(newConflicts) + + reversedRoots.clear() + reversedRoots.addAll(newReversedRoots) + + rebuildTree() + } + }) + } + + private fun rebuildTree() { + val builder = MyTreeModelBuilder(project, groupingSupport.grouping) + builder.addConflicts(conflicts) + val newRoot = builder.build().root + + tableModel.setRoot(newRoot as TreeNode) + TreeUtil.expandAll(table.tree) + } + + private fun showMergeWindowForSelection() { + val conflicts = getSelectedConflicts().filter { mergeHandler.canResolveConflict(it) }.toList() + if (conflicts.isEmpty()) return + + val reversed = HashSet(reversedRoots) + + for (conflict in conflicts) { + val file = conflict.filePath.virtualFile + MergeConflictResolveUtil.showMergeWindow(project, file) { + mergeHandler.resolveConflict(conflict, reversed.contains(conflict.root)) + } + } + } + + private fun acceptConflictSideForSelection(takeTheirs: Boolean) { + val conflicts = getSelectedConflicts() + if (conflicts.isEmpty()) return + + val reversed = HashSet(reversedRoots) + + runBackgroundableTask(StringUtil.pluralize("Resolving Conflict", conflicts.size), project, true) { + mergeHandler.acceptOneVersion(conflicts, reversed, takeTheirs) + } + } + + + private class PathColumn : ColumnInfo, Any?>("Path") { + override fun valueOf(node: ChangesBrowserNode<*>): Any? = node.userObject + override fun getColumnClass(): Class<*> = TreeTableModel::class.java + } + + private inner class YoursColumn : BaseColumn("Yours") { + override fun valueOf(o: ChangesBrowserNode<*>): String? { + val c = o.conflict ?: return null + val status = c.getStatus(ConflictSide.OURS, reversedRoots.contains(c.root)) + return status.name + } + } + + private inner class TheirsColumn : BaseColumn("Theirs") { + override fun valueOf(o: ChangesBrowserNode<*>): String? { + val c = o.conflict ?: return null + val status = c.getStatus(ConflictSide.THEIRS, reversedRoots.contains(c.root)) + return status.name + } + } + + private abstract class BaseColumn(name: String) : ColumnInfo, String>(name) { + protected val ChangesBrowserNode<*>.conflict: GitConflict? + get() = when (this) { + is ConflictChangesBrowserNode -> this.userObject + else -> null + } + } + + private inner class ResolveAction : DumbAwareAction("Resolve", null, AllIcons.Vcs.Merge) { + override fun actionPerformed(e: AnActionEvent) { + showMergeWindowForSelection() + } + } + + private inner class AcceptSideAction(val takeTheirs: Boolean) : + DumbAwareAction(if (takeTheirs) "Accept Theirs" else "Accept Yours", null, + if (takeTheirs) AllIcons.Vcs.Arrow_left else AllIcons.Vcs.Arrow_right) { + override fun actionPerformed(e: AnActionEvent) { + acceptConflictSideForSelection(takeTheirs) + } + } + + private inner class MainPanel : JPanel(BorderLayout()), DataProvider { + override fun getData(dataId: String): Any? { + if (ChangesGroupingSupport.KEY.`is`(dataId)) { + return groupingSupport + } + else if (CommonDataKeys.NAVIGATABLE_ARRAY.`is`(dataId)) { + return ChangesUtil.getNavigatableArray(project, getSelectedConflicts().mapNotNull { it.filePath.virtualFile }.stream()) + } + return null + } + } +} + +private class MyTreeModelBuilder(project: Project, grouping: ChangesGroupingPolicyFactory) : TreeModelBuilder(project, grouping) { + fun addConflicts(conflicts: List) { + for (conflict in conflicts) { + insertChangeNode(conflict.filePath, myRoot, ConflictChangesBrowserNode(conflict)) + } + } +} + +private class ConflictChangesBrowserNode(conflict: GitConflict) : ChangesBrowserNode(conflict) { + override fun isFile(): Boolean = true + override fun isDirectory(): Boolean = false + + override fun render(renderer: ChangesBrowserNodeRenderer, selected: Boolean, expanded: Boolean, hasFocus: Boolean) { + val filePath = getUserObject().filePath + renderer.appendFileName(filePath.virtualFile, filePath.name, FileStatus.MERGED_WITH_CONFLICTS.color) + + if (renderer.isShowFlatten) { + appendParentPath(renderer, filePath.parentPath) + } + + if (!renderer.isShowFlatten && fileCount != 1 || directoryCount != 0) { + appendCount(renderer) + } + + renderer.setIcon(filePath.fileType, filePath.isDirectory || !isLeaf) + } + + override fun getTextPresentation(): String { + return getUserObject().filePath.name + } + + override fun toString(): String { + return FileUtil.toSystemDependentName(getUserObject().filePath.path) + } + + override fun compareUserObjects(o2: GitConflict): Int { + return compareFilePaths(getUserObject().filePath, o2.filePath) + } +} diff --git a/plugins/git4idea/src/git4idea/conflicts/GitMergeHandler.java b/plugins/git4idea/src/git4idea/conflicts/GitMergeHandler.java new file mode 100644 index 000000000000..84f3cb562a54 --- /dev/null +++ b/plugins/git4idea/src/git4idea/conflicts/GitMergeHandler.java @@ -0,0 +1,197 @@ +// Copyright 2000-2019 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. +package git4idea.conflicts; + +import com.intellij.diff.merge.MergeCallback; +import com.intellij.diff.merge.MergeResult; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; +import com.intellij.openapi.vcs.merge.MergeData; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; +import git4idea.merge.GitDefaultMergeDialogCustomizer; +import git4idea.merge.GitMergeUtil; +import git4idea.repo.GitConflict; +import git4idea.repo.GitConflict.ConflictSide; +import git4idea.repo.GitConflict.Status; +import git4idea.repo.GitConflictsHolder; +import git4idea.repo.GitRepository; +import git4idea.repo.GitRepositoryManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +public class GitMergeHandler { + private static final Logger LOG = Logger.getInstance(GitMergeHandler.class); + + @NotNull private final Project myProject; + @NotNull private final GitDefaultMergeDialogCustomizer myDialogCustomizer; + + public GitMergeHandler(@NotNull Project project) { + myProject = project; + myDialogCustomizer = new GitDefaultMergeDialogCustomizer(project); + } + + public boolean canResolveConflict(@NotNull GitConflict conflict) { + VirtualFile file = conflict.getFilePath().getVirtualFile(); + if (file == null) return false; + if (file.isDirectory()) return false; // Can't handle conflicts in submodules + return conflict.getStatus(ConflictSide.OURS) != Status.DELETED || + conflict.getStatus(ConflictSide.THEIRS) != Status.DELETED; + } + + @NotNull + public Resolver resolveConflict(@NotNull GitConflict conflict, boolean isReversed) throws VcsException { + VirtualFile root = conflict.getRoot(); + FilePath path = conflict.getFilePath(); + + VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path.getPath()); + if (file == null) throw new VcsException("Can't find file for " + path); + + MergeData mergeData = GitMergeUtil.loadMergeData(myProject, root, path, isReversed); + + String windowTitle = myDialogCustomizer.getMergeWindowTitle(file); + String leftTitle = myDialogCustomizer.getLeftPanelTitle(file); + String centerTitle = myDialogCustomizer.getCenterPanelTitle(file); + String rightTitle = myDialogCustomizer.getRightPanelTitle(file, mergeData.LAST_REVISION_NUMBER); + + return new Resolver(myProject, conflict, isReversed, file, mergeData, + windowTitle, ContainerUtil.list(leftTitle, centerTitle, rightTitle)); + } + + public void acceptOneVersion(@NotNull Collection conflicts, + @NotNull Collection reversedRoots, + boolean takeTheirs) throws VcsException { + try { + MultiMap byRoot = groupConflictsByRoot(conflicts); + + for (VirtualFile root : byRoot.keySet()) { + Collection rootConflicts = byRoot.get(root); + boolean isReversed = reversedRoots.contains(root); + ConflictSide side = isReversed == takeTheirs ? ConflictSide.OURS : ConflictSide.THEIRS; + + GitMergeUtil.acceptOneVersion(myProject, root, rootConflicts, side); + GitMergeUtil.markConflictResolved(myProject, root, rootConflicts, side); + } + } + finally { + VcsDirtyScopeManager.getInstance(myProject).filePathsDirty(ContainerUtil.map(conflicts, GitConflict::getFilePath), null); + } + } + + @NotNull + public static MultiMap groupConflictsByRoot(@NotNull Collection conflicts) { + MultiMap byRoot = MultiMap.create(); + for (GitConflict conflict : conflicts) { + byRoot.putValue(conflict.getRoot(), conflict); + } + return byRoot; + } + + public static class Resolver { + @NotNull private final Project myProject; + @NotNull private final GitConflict myConflict; + private final boolean myIsReversed; + @NotNull private final MergeData myMergeData; + @NotNull private final VirtualFile myFile; + + @NotNull private final String myWindowTitle; + @NotNull private final List myContentTitles; + + private volatile boolean myIsValid = true; + + private Resolver(@NotNull Project project, + @NotNull GitConflict conflict, + boolean isReversed, + @NotNull VirtualFile file, + @NotNull MergeData mergeData, + @NotNull String windowTitle, + @NotNull List contentTitles) { + myProject = project; + myConflict = conflict; + myIsReversed = isReversed; + myMergeData = mergeData; + myFile = file; + myWindowTitle = windowTitle; + myContentTitles = contentTitles; + } + + @NotNull + public Project getProject() { + return myProject; + } + + @NotNull + public VirtualFile getVirtualFile() { + return myFile; + } + + @NotNull + public MergeData getMergeData() { + return myMergeData; + } + + public void onConflictResolved(@NotNull MergeResult result) { + if (result != MergeResult.CANCEL) { + try { + GitMergeUtil.markConflictResolved(myProject, myConflict.getRoot(), singletonList(myConflict), getResolutionSide(result)); + } + catch (VcsException e) { + LOG.error(String.format("Unexpected exception during the git operation: file - %s)", myConflict.getFilePath()), e); + } + } + VcsDirtyScopeManager.getInstance(myProject).filesDirty(singletonList(myFile), emptyList()); + } + + @Nullable + private ConflictSide getResolutionSide(@NotNull MergeResult result) { + switch (result) { + case LEFT: + return !myIsReversed ? ConflictSide.OURS : ConflictSide.THEIRS; + case RIGHT: + return myIsReversed ? ConflictSide.OURS : ConflictSide.THEIRS; + default: + return null; + } + } + + @NotNull + public String getWindowTitle() { + return myWindowTitle; + } + + @NotNull + public List getContentTitles() { + return myContentTitles; + } + + public boolean checkIsValid() { + if (myIsValid) { + GitRepository repository = GitRepositoryManager.getInstance(myProject).getRepositoryForRoot(myConflict.getRoot()); + if (repository == null) return true; + myIsValid = repository.getConflictsHolder().findConflict(myConflict.getFilePath()) != null; + } + return myIsValid; + } + + public void addListener(@NotNull MergeCallback.Listener listener, @NotNull Disposable disposable) { + myProject.getMessageBus().connect(disposable).subscribe(GitConflictsHolder.CONFLICTS_CHANGE, (repo) -> { + if (myIsValid && myConflict.getRoot().equals(repo.getRoot())) { + if (!checkIsValid()) { + listener.fireConflictInvalid(); + } + } + }); + } + } +} diff --git a/plugins/git4idea/src/git4idea/conflicts/MergeConflictResolveUtil.kt b/plugins/git4idea/src/git4idea/conflicts/MergeConflictResolveUtil.kt new file mode 100644 index 000000000000..b79d30408a5d --- /dev/null +++ b/plugins/git4idea/src/git4idea/conflicts/MergeConflictResolveUtil.kt @@ -0,0 +1,139 @@ +// Copyright 2000-2019 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. +package git4idea.conflicts + +import com.intellij.diff.DiffDialogHints +import com.intellij.diff.DiffManagerEx +import com.intellij.diff.DiffRequestFactory +import com.intellij.diff.chains.DiffRequestProducerException +import com.intellij.diff.merge.* +import com.intellij.openapi.Disposable +import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.fileEditor.FileEditor +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.runBackgroundableTask +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.WindowWrapper +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.UserDataHolder +import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager +import com.intellij.openapi.vcs.merge.MergeDialogCustomizer +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.ui.EditorNotificationPanel +import com.intellij.ui.EditorNotifications +import com.intellij.ui.LightColors +import com.intellij.util.Consumer +import com.intellij.util.ui.UIUtil +import org.jetbrains.annotations.CalledInAwt +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent +import javax.swing.JFrame + +object MergeConflictResolveUtil { + private val ACTIVE_MERGE_WINDOW = Key.create("ResolveConflictsWindow") + + @CalledInAwt + fun showMergeWindow(project: Project, file: VirtualFile?, resolverComputer: () -> GitMergeHandler.Resolver) { + if (focusActiveMergeWindow(file)) return + + val title = if (file != null) MergeDialogCustomizer().getMergeWindowTitle(file) else "Merge" + + val windowHandler = Consumer { wrapper -> putActiveWindowKey(project, wrapper, file) } + val hints = DiffDialogHints(WindowWrapper.Mode.FRAME, null, windowHandler) + + val producer = MyProducer(project, title, resolverComputer) + + DiffManagerEx.getInstance().showMergeBuiltin(project, producer, hints) + } + + private class MyProducer(val project: Project, + val title: String, + val resolverComputer: () -> GitMergeHandler.Resolver) : MergeRequestProducer { + override fun getName(): String = title + + override fun process(context: UserDataHolder, indicator: ProgressIndicator): MergeRequest { + try { + val resolver = resolverComputer() + + val mergeData = resolver.mergeData + val byteContents = listOf(mergeData.CURRENT, mergeData.ORIGINAL, mergeData.LAST) + + val request = runReadAction { + DiffRequestFactory.getInstance().createMergeRequest(project, resolver.virtualFile, byteContents, + resolver.windowTitle, resolver.contentTitles) + } + MergeUtil.putRevisionInfos(request, mergeData) + MergeCallback.register(request, MyMergeCallback(resolver)) + return request + } + catch (e: Throwable) { + throw DiffRequestProducerException(e) + } + } + } + + private fun putActiveWindowKey(project: Project, wrapper: WindowWrapper, file: VirtualFile?) { + if (file == null) return + val window = wrapper.window + if (window !is JFrame) return + + file.putUserData(ACTIVE_MERGE_WINDOW, wrapper) + EditorNotifications.getInstance(project).updateNotifications(file) + + window.addWindowListener(object : WindowAdapter() { + override fun windowClosed(e: WindowEvent?) { + window.removeWindowListener(this) + file.putUserData(ACTIVE_MERGE_WINDOW, null) + EditorNotifications.getInstance(project).updateNotifications(file) + } + }) + } + + private fun focusActiveMergeWindow(file: VirtualFile?): Boolean { + val wrapper = file?.getUserData(ACTIVE_MERGE_WINDOW) ?: return false + UIUtil.toFront(wrapper.window) + return true + } + + private class MyMergeCallback(private val resolver: GitMergeHandler.Resolver) : MergeCallback() { + override fun applyResult(result: MergeResult) { + val project = resolver.project + val file = resolver.virtualFile + + val document = FileDocumentManager.getInstance().getCachedDocument(file) + if (document != null) FileDocumentManager.getInstance().saveDocument(document) + + MergeUtil.reportProjectFileChangeIfNeeded(project, file) + + if (result != MergeResult.CANCEL) { + runBackgroundableTask("Finishing Conflict Resolve", project, false) { + resolver.onConflictResolved(result) + } + } + } + + override fun checkIsValid(): Boolean { + return resolver.checkIsValid() + } + + override fun addListener(listener: Listener, disposable: Disposable) { + resolver.addListener(listener, disposable) + } + } + + + class NotificationProvider : EditorNotifications.Provider() { + private val KEY = Key.create("MergeConflictResolveUtil.NotificationProvider") + + override fun getKey(): Key = KEY + + override fun createNotificationPanel(file: VirtualFile, fileEditor: FileEditor, project: Project): EditorNotificationPanel? { + val wrapper = file.getUserData(ACTIVE_MERGE_WINDOW) ?: return null + val panel = EditorNotificationPanel(LightColors.SLIGHTLY_GREEN) + panel.setText("Merge conflicts resolve in progress.") + panel.createActionLabel("Focus Window") { UIUtil.toFront(wrapper.window) } + panel.createActionLabel("Cancel Resolve") { wrapper.close() } + return panel + } + } +} \ No newline at end of file diff --git a/plugins/git4idea/src/git4idea/merge/GitMergeProvider.java b/plugins/git4idea/src/git4idea/merge/GitMergeProvider.java index 61d334b3a728..5b22a56872c7 100644 --- a/plugins/git4idea/src/git4idea/merge/GitMergeProvider.java +++ b/plugins/git4idea/src/git4idea/merge/GitMergeProvider.java @@ -17,9 +17,10 @@ import com.intellij.vcsUtil.VcsUtil; import git4idea.GitUtil; import git4idea.commands.Git; import git4idea.commands.GitCommand; -import git4idea.commands.GitCommandResult; import git4idea.commands.GitLineHandler; import git4idea.i18n.GitBundle; +import git4idea.repo.GitConflict; +import git4idea.repo.GitConflict.ConflictSide; import git4idea.repo.GitRepository; import git4idea.util.GitFileUtils; import git4idea.util.StringScanner; @@ -74,7 +75,7 @@ public class GitMergeProvider implements MergeProvider2 { for (GitRepository repository : GitUtil.getRepositoryManager(project).getRepositories()) { boolean reverse; if (reverseOrDetect == ReverseRequest.DETECT) { - reverse = repository.getState().equals(GitRepository.State.REBASING); + reverse = isReverseRoot(repository); } else { reverse = reverseOrDetect == ReverseRequest.REVERSE; @@ -96,7 +97,7 @@ public class GitMergeProvider implements MergeProvider2 { VcsRunnable runnable = new VcsRunnable() { @Override public void run() throws VcsException { - mergeDataRef.set(GitMergeUtil.loadMergeData(myProject, root, path, myReverseRoots.contains(root))); + mergeDataRef.set(loadMergeData(myProject, root, path, myReverseRoots.contains(root))); } }; VcsUtil.runVcsProcessWithProgress(runnable, GitBundle.message("merge.load.files"), false, myProject); @@ -147,25 +148,6 @@ public class GitMergeProvider implements MergeProvider2 { GitConflict.Status myStatusYours; } - private static class GitConflict { - @NotNull public final FilePath myPath; - @NotNull public final VirtualFile myRoot; - @NotNull public final Status myStatusTheirs; - @NotNull public final Status myStatusYours; - - private GitConflict(@NotNull FilePath path, @NotNull VirtualFile root, @NotNull Status statusTheirs, @NotNull Status statusYours) { - myPath = path; - myRoot = root; - myStatusTheirs = statusTheirs; - myStatusYours = statusYours; - } - - enum Status { - MODIFIED, // modified on the branch - DELETED // deleted on the branch - } - } - /** * The merge session, it queries conflict information. */ @@ -230,7 +212,7 @@ public class GitMergeProvider implements MergeProvider2 { if (c.myStatusYours == null) { c.myStatusYours = GitConflict.Status.DELETED; } - myConflicts.put(f, new GitConflict(VcsUtil.getFilePath(f), root, c.myStatusTheirs, c.myStatusYours)); + myConflicts.put(f, new GitConflict(root, VcsUtil.getFilePath(f), c.myStatusYours, c.myStatusTheirs)); } } currentBranchName = GitDefaultMergeDialogCustomizerKt.getSingleCurrentBranchName(filesByRoot.keySet()); @@ -264,42 +246,14 @@ public class GitMergeProvider implements MergeProvider2 { for (VirtualFile root : byRoot.keySet()) { Collection conflicts = byRoot.get(root); - - List toAdd = new ArrayList<>(); - List toDelete = new ArrayList<>(); - - for (GitConflict c : conflicts) { - boolean isReversed = myReverseRoots.contains(c.myRoot); - - GitConflict.Status status; - switch (resolution) { - case AcceptedTheirs: - status = !isReversed ? c.myStatusTheirs : c.myStatusYours; - break; - case AcceptedYours: - status = isReversed ? c.myStatusTheirs : c.myStatusYours; - break; - case Merged: - status = GitConflict.Status.MODIFIED; - break; - default: - throw new IllegalArgumentException("Unsupported resolution: " + resolution); - } - - if (status == GitConflict.Status.MODIFIED) { - toAdd.add(c.myPath); - } - else { - toDelete.add(c.myPath); - } - } + ConflictSide resolutionSide = resolution != Resolution.Merged ? getAcceptedConflictSide(resolution, root) : null; try { - GitFileUtils.addPathsForce(myProject, root, toAdd); - GitFileUtils.deletePaths(myProject, root, toDelete); + markConflictResolved(myProject, root, conflicts, resolutionSide); } catch (VcsException e) { - LOG.error(String.format("Unexpected exception during the git operation: modified - %s deleted - %s)", toAdd, toDelete), e); + LOG.error(String.format("Unexpected exception during the git operation. Files - %s", + ContainerUtil.map(conflicts, GitConflict::getFilePath)), e); } } } @@ -312,28 +266,21 @@ public class GitMergeProvider implements MergeProvider2 { for (VirtualFile root : byRoot.keySet()) { Collection conflicts = byRoot.get(root); - boolean isReversed = myReverseRoots.contains(root); - boolean acceptYours = !isReversed ? resolution == Resolution.AcceptedYours - : resolution == Resolution.AcceptedTheirs; + ConflictSide conflictSide = getAcceptedConflictSide(resolution, root); - List filesToCheckout = ContainerUtil.mapNotNull(conflicts, c -> { - GitConflict.Status status = acceptYours ? c.myStatusYours : c.myStatusTheirs; - return status == GitConflict.Status.MODIFIED ? c.myPath : null; - }); - - String parameter = acceptYours ? "--ours" : "--theirs"; - - for (List paths : VcsFileUtil.chunkPaths(root, filesToCheckout)) { - GitLineHandler handler = new GitLineHandler(myProject, root, GitCommand.CHECKOUT); - handler.addParameters(parameter); - handler.endOptions(); - handler.addParameters(paths); - GitCommandResult result = Git.getInstance().runCommand(handler); - if (!result.success()) throw new VcsException(result.getErrorOutputAsJoinedString()); - } + acceptOneVersion(myProject, root, conflicts, conflictSide); } } + @NotNull + private ConflictSide getAcceptedConflictSide(@NotNull Resolution resolution, @NotNull VirtualFile root) { + assert resolution == Resolution.AcceptedYours || resolution == Resolution.AcceptedTheirs; + boolean isReversed = myReverseRoots.contains(root); + boolean acceptYours = !isReversed ? resolution == Resolution.AcceptedYours + : resolution == Resolution.AcceptedTheirs; + return acceptYours ? ConflictSide.OURS : ConflictSide.THEIRS; + } + @NotNull private MultiMap groupConflictsByRoot(@NotNull List files) { MultiMap byRoot = MultiMap.create(); @@ -344,7 +291,7 @@ public class GitMergeProvider implements MergeProvider2 { continue; } - byRoot.putValue(c.myRoot, c); + byRoot.putValue(c.getRoot(), c); } return byRoot; } @@ -352,7 +299,7 @@ public class GitMergeProvider implements MergeProvider2 { /** * The column shows either "yours" or "theirs" status */ - class StatusColumn extends ColumnInfo { + private class StatusColumn extends ColumnInfo { private final boolean myIsLast; StatusColumn(boolean isLast, @Nullable String branchName) { @@ -367,9 +314,9 @@ public class GitMergeProvider implements MergeProvider2 { LOG.error("No conflict for the file " + file); return ""; } - boolean isReversed = myReverseRoots.contains(c.myRoot); - GitConflict.Status currentStatus = !isReversed ? c.myStatusYours : c.myStatusTheirs; - GitConflict.Status lastStatus = isReversed ? c.myStatusYours : c.myStatusTheirs; + boolean isReversed = myReverseRoots.contains(c.getRoot()); + GitConflict.Status currentStatus = c.getStatus(ConflictSide.OURS, isReversed); + GitConflict.Status lastStatus = c.getStatus(ConflictSide.THEIRS, isReversed); GitConflict.Status status = myIsLast ? lastStatus : currentStatus; switch (status) { case MODIFIED: diff --git a/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java b/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java index a3f809f5c10e..80ad1a3f73fa 100644 --- a/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java +++ b/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java @@ -33,13 +33,11 @@ import com.intellij.vcsUtil.VcsFileUtil; import git4idea.GitRevisionNumber; import git4idea.GitUtil; import git4idea.GitVcs; -import git4idea.commands.Git; -import git4idea.commands.GitCommand; -import git4idea.commands.GitLineHandler; -import git4idea.commands.GitLineHandlerListener; +import git4idea.commands.*; import git4idea.history.GitHistoryUtils; import git4idea.i18n.GitBundle; import git4idea.index.GitIndexUtil; +import git4idea.repo.GitConflict; import git4idea.repo.GitRepository; import git4idea.util.GitFileUtils; import git4idea.util.StringScanner; @@ -50,6 +48,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -450,4 +449,65 @@ public class GitMergeUtil { if (pathAmbiguous[0]) return null; return result[0]; } + + public static void acceptOneVersion(@NotNull Project project, + @NotNull VirtualFile root, + @NotNull Collection conflicts, + @NotNull GitConflict.ConflictSide side) throws VcsException { + boolean isCurrent = side == GitConflict.ConflictSide.OURS; + + for (GitConflict conflict : conflicts) { + assert root.equals(conflict.getRoot()); + } + + List toCheckout = new ArrayList<>(); + + for (GitConflict conflict : conflicts) { + GitConflict.Status status = conflict.getStatus(side); + FilePath filePath = conflict.getFilePath(); + + if (status == GitConflict.Status.MODIFIED) { + toCheckout.add(filePath); + } + } + + for (List paths : VcsFileUtil.chunkPaths(root, toCheckout)) { + GitLineHandler handler = new GitLineHandler(project, root, GitCommand.CHECKOUT); + handler.addParameters(isCurrent ? "--ours" : "--theirs"); + handler.endOptions(); + handler.addParameters(paths); + + GitCommandResult result = Git.getInstance().runCommand(handler); + if (!result.success()) throw new VcsException(result.getErrorOutputAsJoinedString()); + } + } + + /** + * + */ + public static void markConflictResolved(@NotNull Project project, + @NotNull VirtualFile root, + @NotNull Collection conflicts, + @Nullable GitConflict.ConflictSide side) throws VcsException { + List toAdd = new ArrayList<>(); + List toDelete = new ArrayList<>(); + + for (GitConflict conflict : conflicts) { + FilePath filePath = conflict.getFilePath(); + + if (side == null || conflict.getStatus(side) == GitConflict.Status.MODIFIED) { + toAdd.add(filePath); + } + else { + toDelete.add(filePath); + } + } + + GitFileUtils.addPathsForce(project, root, toAdd); + GitFileUtils.deletePaths(project, root, toDelete); + } + + public static boolean isReverseRoot(@NotNull GitRepository repository) { + return repository.getState().equals(GitRepository.State.REBASING); + } } diff --git a/plugins/git4idea/src/git4idea/repo/GitConflict.java b/plugins/git4idea/src/git4idea/repo/GitConflict.java new file mode 100644 index 000000000000..edf4cde9cad1 --- /dev/null +++ b/plugins/git4idea/src/git4idea/repo/GitConflict.java @@ -0,0 +1,62 @@ +// Copyright 2000-2019 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. +package git4idea.repo; + +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +public class GitConflict { + @NotNull private final VirtualFile myRoot; + @NotNull private final FilePath myFilePath; + @NotNull private final Status myOurStatus; + @NotNull private final Status myTheirStatus; + + public GitConflict(@NotNull VirtualFile root, + @NotNull FilePath filePath, + @NotNull Status ourStatus, + @NotNull Status theirStatus) { + myRoot = root; + myFilePath = filePath; + myOurStatus = ourStatus; + myTheirStatus = theirStatus; + } + + @NotNull + public VirtualFile getRoot() { + return myRoot; + } + + @NotNull + public FilePath getFilePath() { + return myFilePath; + } + + @NotNull + public Status getStatus(@NotNull ConflictSide side) { + return getStatus(side, false); + } + + @NotNull + public Status getStatus(@NotNull ConflictSide side, boolean isReversed) { + if (side == ConflictSide.OURS) { + return !isReversed ? myOurStatus : myTheirStatus; + } + else { + return !isReversed ? myTheirStatus : myOurStatus; + } + } + + public enum Status { + MODIFIED, // modified on the branch + DELETED // deleted on the branch + } + + /** + * Conflict side in Git terms (--ours or --theirs), ignoring IDE-level visible sides reversal. + * + * @see git4idea.merge.GitMergeUtil#isReverseRoot(GitRepository) + */ + public enum ConflictSide { + OURS, THEIRS + } +} diff --git a/plugins/git4idea/src/git4idea/repo/GitConflictsHolder.java b/plugins/git4idea/src/git4idea/repo/GitConflictsHolder.java new file mode 100644 index 000000000000..7e5f76cd8ac0 --- /dev/null +++ b/plugins/git4idea/src/git4idea/repo/GitConflictsHolder.java @@ -0,0 +1,69 @@ +// Copyright 2000-2019 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. +package git4idea.repo; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.progress.util.BackgroundTaskUtil; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.changes.VcsDirtyScope; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.messages.Topic; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class GitConflictsHolder implements Disposable { + public static final Topic CONFLICTS_CHANGE = Topic.create("GitConflictsHolder change", ConflictsListener.class); + + @NotNull private final GitRepository myRepository; + @NotNull private final List myConflicts = new ArrayList<>(); + + private final Object LOCK = new Object(); + + public GitConflictsHolder(@NotNull GitRepository repository) { + myRepository = repository; + } + + @NotNull + public List getConflicts() { + synchronized (LOCK) { + return new ArrayList<>(myConflicts); + } + } + + @Override + public void dispose() { + synchronized (LOCK) { + myConflicts.clear(); + } + } + + @Nullable + public GitConflict findConflict(@NotNull FilePath path) { + synchronized (LOCK) { + return ContainerUtil.find(myConflicts, it -> it.getFilePath().equals(path)); + } + } + + public void refresh(@NotNull VcsDirtyScope scope, @NotNull Collection conflicts) { + synchronized (LOCK) { + Map map = new HashMap<>(); + for (GitConflict conflict : myConflicts) { + if (scope.belongsTo(conflict.getFilePath())) continue; + map.put(conflict.getFilePath(), conflict); + } + + for (GitConflict conflict : conflicts) { + map.put(conflict.getFilePath(), conflict); + } + + myConflicts.clear(); + myConflicts.addAll(map.values()); + } + BackgroundTaskUtil.syncPublisher(myRepository.getProject(), CONFLICTS_CHANGE).conflictsChanged(myRepository); + } + + public interface ConflictsListener { + void conflictsChanged(@NotNull GitRepository repository); + } +} diff --git a/plugins/git4idea/src/git4idea/repo/GitRepository.java b/plugins/git4idea/src/git4idea/repo/GitRepository.java index b6a8c04bc45a..6c64f267efd6 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepository.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepository.java @@ -63,6 +63,9 @@ public interface GitRepository extends Repository { @NotNull GitUntrackedFilesHolder getUntrackedFilesHolder(); + @NotNull + GitConflictsHolder getConflictsHolder(); + @NotNull GitRepoInfo getInfo(); diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java index 155ff0a2f444..d46fee1bd46f 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java @@ -32,7 +32,6 @@ import static com.intellij.util.containers.ContainerUtil.newHashMap; import static com.intellij.util.containers.ContainerUtil.newLinkedHashSet; public class GitRepositoryImpl extends RepositoryImpl implements GitRepository { - @NotNull private final GitVcs myVcs; @NotNull private final GitRepositoryReader myReader; @NotNull private final VirtualFile myGitDir; @@ -40,6 +39,7 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository { @Nullable private final GitUntrackedFilesHolder myUntrackedFilesHolder; @Nullable private final GitRepositoryIgnoredFilesHolder myIgnoredRepositoryFilesHolder; + @Nullable private final GitConflictsHolder myConflictsHolder; @NotNull private volatile GitRepoInfo myInfo; @@ -58,14 +58,19 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository { if (!light) { myUntrackedFilesHolder = new GitUntrackedFilesHolder(this, myRepositoryFiles); Disposer.register(this, myUntrackedFilesHolder); + myIgnoredRepositoryFilesHolder = new GitRepositoryIgnoredFilesHolder(project, this, GitRepositoryManager.getInstance(project), Git.getInstance()); Disposer.register(this, myIgnoredRepositoryFilesHolder); myIgnoredRepositoryFilesHolder.addUpdateStateListener(new MyRepositoryIgnoredHolderUpdateListener(getProject())); + + myConflictsHolder = new GitConflictsHolder(this); + Disposer.register(this, myConflictsHolder); } else { myUntrackedFilesHolder = null; myIgnoredRepositoryFilesHolder = null; + myConflictsHolder = null; } } @@ -121,6 +126,15 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository { return myUntrackedFilesHolder; } + @NotNull + @Override + public GitConflictsHolder getConflictsHolder() { + if (myConflictsHolder == null) { + throw new IllegalStateException("Using conflicts holder with light git repository instance " + this); + } + return myConflictsHolder; + } + @Override @NotNull public GitRepoInfo getInfo() { diff --git a/plugins/git4idea/src/git4idea/status/GitChangeProvider.java b/plugins/git4idea/src/git4idea/status/GitChangeProvider.java index a131747c90f7..3fca13b206ea 100644 --- a/plugins/git4idea/src/git4idea/status/GitChangeProvider.java +++ b/plugins/git4idea/src/git4idea/status/GitChangeProvider.java @@ -19,6 +19,7 @@ import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.changes.GitChangeUtils; import git4idea.commands.Git; +import git4idea.repo.GitConflictsHolder; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; import org.jetbrains.annotations.NotNull; @@ -95,6 +96,9 @@ public class GitChangeProvider implements ChangeProvider { builder.processUnversionedFile(f); holder.unversioned(f); } + + GitConflictsHolder conflictsHolder = repo.getConflictsHolder(); + conflictsHolder.refresh(dirtyScope, collector.getConflicts()); } holder.feedBuilder(builder); diff --git a/plugins/git4idea/src/git4idea/status/GitChangesCollector.java b/plugins/git4idea/src/git4idea/status/GitChangesCollector.java index 748ad0a5d2ac..a063ccb1a6b7 100644 --- a/plugins/git4idea/src/git4idea/status/GitChangesCollector.java +++ b/plugins/git4idea/src/git4idea/status/GitChangesCollector.java @@ -15,7 +15,6 @@ */ package git4idea.status; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -35,6 +34,8 @@ import git4idea.commands.Git; import git4idea.commands.GitCommand; import git4idea.commands.GitHandler; import git4idea.commands.GitLineHandler; +import git4idea.repo.GitConflict; +import git4idea.repo.GitConflict.Status; import git4idea.repo.GitRepository; import git4idea.repo.GitUntrackedFilesHolder; import org.jetbrains.annotations.NotNull; @@ -54,28 +55,31 @@ import java.util.*; * @author Kirill Likhodedov */ class GitChangesCollector { - private static final Logger LOG = Logger.getInstance(GitChangesCollector.class); @NotNull private final Project myProject; - @NotNull private final VirtualFile myVcsRoot; - - @NotNull private final VcsDirtyScope myDirtyScope; + @NotNull private final Git myGit; @NotNull private final ChangeListManager myChangeListManager; @NotNull private final ProjectLevelVcsManager myVcsManager; @NotNull private final AbstractVcs myVcs; - + @NotNull private final VcsDirtyScope myDirtyScope; @NotNull private final GitRepository myRepository; + @NotNull private final VirtualFile myVcsRoot; + private final Collection myChanges = new HashSet<>(); private final Set myUnversionedFiles = new HashSet<>(); - @NotNull private final Git myGit; + private final Collection myConflicts = new HashSet<>(); /** * Collects the changes from git command line and returns the instance of GitNewChangesCollector from which these changes can be retrieved. * This may be lengthy. */ @NotNull - static GitChangesCollector collect(@NotNull Project project, @NotNull Git git, @NotNull ChangeListManager changeListManager, - @NotNull ProjectLevelVcsManager vcsManager, @NotNull AbstractVcs vcs, - @NotNull VcsDirtyScope dirtyScope, @NotNull GitRepository repository) throws VcsException { + static GitChangesCollector collect(@NotNull Project project, + @NotNull Git git, + @NotNull ChangeListManager changeListManager, + @NotNull ProjectLevelVcsManager vcsManager, + @NotNull AbstractVcs vcs, + @NotNull VcsDirtyScope dirtyScope, + @NotNull GitRepository repository) throws VcsException { return new GitChangesCollector(project, git, changeListManager, vcsManager, vcs, dirtyScope, repository); } @@ -89,17 +93,25 @@ class GitChangesCollector { return myChanges; } - private GitChangesCollector(@NotNull Project project, @NotNull Git git, @NotNull ChangeListManager changeListManager, - @NotNull ProjectLevelVcsManager vcsManager, @NotNull AbstractVcs vcs, - @NotNull VcsDirtyScope dirtyScope, @NotNull GitRepository repository) throws VcsException { + Collection getConflicts() { + return myConflicts; + } + + private GitChangesCollector(@NotNull Project project, + @NotNull Git git, + @NotNull ChangeListManager changeListManager, + @NotNull ProjectLevelVcsManager vcsManager, + @NotNull AbstractVcs vcs, + @NotNull VcsDirtyScope dirtyScope, + @NotNull GitRepository repository) throws VcsException { myProject = project; + myGit = git; myChangeListManager = changeListManager; myVcsManager = vcsManager; myVcs = vcs; myDirtyScope = dirtyScope; - myVcsRoot = repository.getRoot(); - myGit = git; myRepository = repository; + myVcsRoot = repository.getRoot(); Collection dirtyPaths = dirtyPaths(); if (!dirtyPaths.isEmpty()) { @@ -236,7 +248,7 @@ class GitChangesCollector { } else if (yStatus == 'T') { reportTypeChanged(filepath, head); } else if (yStatus == 'U') { - reportConflict(filepath, head); + reportConflict(filepath, head, Status.MODIFIED, Status.MODIFIED); } else { throwYStatus(output, handler, line, xStatus, yStatus); } @@ -263,7 +275,7 @@ class GitChangesCollector { } else if (yStatus == 'D') { // added + deleted => no change (from IDEA point of view). } else if (yStatus == 'U' || yStatus == 'A') { // AU - unmerged, added by us; AA - unmerged, both added - reportConflict(filepath, head); + reportConflict(filepath, head, Status.MODIFIED, Status.MODIFIED); } else { throwYStatus(output, handler, line, xStatus, yStatus); } @@ -273,21 +285,22 @@ class GitChangesCollector { if (yStatus == 'M' || yStatus == ' ' || yStatus == 'T') { reportDeleted(filepath, head); } else if (yStatus == 'U') { // DU - unmerged, deleted by us - reportConflict(filepath, head); + reportConflict(filepath, head, Status.DELETED, Status.MODIFIED); } else if (yStatus == 'D') { // DD - unmerged, both deleted - // TODO - // currently not displaying, because "both deleted" conflicts can't be handled by our conflict resolver. - // see IDEA-63156 + reportConflict(filepath, head, Status.DELETED, Status.DELETED); } else { throwYStatus(output, handler, line, xStatus, yStatus); } break; case 'U': - if (yStatus == 'U' || yStatus == 'A' || yStatus == 'D' || yStatus == 'T') { - // UU - unmerged, both modified; UD - unmerged, deleted by them; UA - unmerged, added by them - reportConflict(filepath, head); - } else { + if (yStatus == 'U' || yStatus == 'A' || yStatus == 'T') { // UU - unmerged, both modified; UA - unmerged, added by them + reportConflict(filepath, head, Status.MODIFIED, Status.MODIFIED); + } + else if (yStatus == 'D') { // UD - unmerged, deleted by them + reportConflict(filepath, head, Status.MODIFIED, Status.DELETED); + } + else { throwYStatus(output, handler, line, xStatus, yStatus); } break; @@ -379,10 +392,15 @@ class GitChangesCollector { reportChange(FileStatus.MODIFIED, before, after); } - private void reportConflict(FilePath filepath, VcsRevisionNumber head) { - ContentRevision before = GitContentRevision.createRevision(filepath, head, myProject); - ContentRevision after = GitContentRevision.createRevision(filepath, null, myProject); - reportChange(FileStatus.MERGED_WITH_CONFLICTS, before, after); + private void reportConflict(FilePath filepath, VcsRevisionNumber head, Status oursStatus, Status theirsStatus) { + myConflicts.add(new GitConflict(myVcsRoot, filepath, oursStatus, theirsStatus)); + + // TODO: currently not displaying "both deleted" conflicts, because they can't be handled by GitMergeProvider (see IDEA-63156) + if (oursStatus != Status.DELETED || theirsStatus != Status.DELETED) { + ContentRevision before = GitContentRevision.createRevision(filepath, head, myProject); + ContentRevision after = GitContentRevision.createRevision(filepath, null, myProject); + reportChange(FileStatus.MERGED_WITH_CONFLICTS, before, after); + } } private void reportChange(FileStatus status, ContentRevision before, ContentRevision after) { diff --git a/plugins/git4idea/tests/git4idea/test/MockGitRepository.java b/plugins/git4idea/tests/git4idea/test/MockGitRepository.java index fe8bf5265f14..13e30e879845 100644 --- a/plugins/git4idea/tests/git4idea/test/MockGitRepository.java +++ b/plugins/git4idea/tests/git4idea/test/MockGitRepository.java @@ -55,6 +55,12 @@ public class MockGitRepository implements GitRepository { throw new UnsupportedOperationException(); } + @NotNull + @Override + public GitConflictsHolder getConflictsHolder() { + throw new UnsupportedOperationException(); + } + @NotNull @Override public GitRepoInfo getInfo() { diff --git a/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml b/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml index 22dce1242e39..5d79e3b7af0c 100644 --- a/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml +++ b/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml @@ -58,6 +58,7 @@ + @@ -66,10 +67,10 @@ + - diff --git a/plugins/gradle/java/resources/META-INF/gradle-java-integration.xml b/plugins/gradle/java/resources/META-INF/gradle-java-integration.xml index 23223407ba4d..8d3f5f1508ba 100644 --- a/plugins/gradle/java/resources/META-INF/gradle-java-integration.xml +++ b/plugins/gradle/java/resources/META-INF/gradle-java-integration.xml @@ -36,8 +36,6 @@ - diff --git a/plugins/gradle/java/src/execution/build/output/GradleJavaOutputParserProvider.java b/plugins/gradle/java/src/execution/build/output/GradleJavaOutputParserProvider.java deleted file mode 100644 index 999248a2579b..000000000000 --- a/plugins/gradle/java/src/execution/build/output/GradleJavaOutputParserProvider.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2000-2017 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. -package org.jetbrains.plugins.gradle.execution.build.output; - -import com.intellij.build.output.BuildOutputParser; -import com.intellij.build.output.JavacOutputParser; -import com.intellij.build.output.KotlincOutputParser; -import com.intellij.openapi.externalSystem.model.ProjectSystemId; -import com.intellij.openapi.externalSystem.model.task.ExternalSystemTask; -import com.intellij.openapi.externalSystem.service.execution.ExternalSystemOutputParserProvider; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.plugins.gradle.util.GradleConstants; - -import java.util.List; - -/** - * @author Vladislav.Soroka - */ -public class GradleJavaOutputParserProvider implements ExternalSystemOutputParserProvider { - @Override - public ProjectSystemId getExternalSystemId() { - return GradleConstants.SYSTEM_ID; - } - - @Override - public List getBuildOutputParsers(ExternalSystemTask task) { - // use javac, kotlinc output parsers for the sync tasks also to handle the compilation output of the 'buildSrc' sources - return ContainerUtil.list(new JavacOutputParser(), new KotlincOutputParser()); - } -} diff --git a/plugins/gradle/java/src/service/resolve/GradleDomainObjectProperty.kt b/plugins/gradle/java/src/service/resolve/GradleDomainObjectProperty.kt new file mode 100644 index 000000000000..49189ac19719 --- /dev/null +++ b/plugins/gradle/java/src/service/resolve/GradleDomainObjectProperty.kt @@ -0,0 +1,10 @@ +// Copyright 2000-2019 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. +package org.jetbrains.plugins.gradle.service.resolve + +import com.intellij.ide.presentation.Presentation +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiType +import org.jetbrains.plugins.groovy.lang.resolve.api.SimpleGroovyProperty + +@Presentation(typeName = "Gradle Domain Object") +class GradleDomainObjectProperty(name: String, type: PsiType?, context: PsiElement) : SimpleGroovyProperty(name, type, context) diff --git a/plugins/gradle/java/src/service/resolve/GradleExtensionsContributor.kt b/plugins/gradle/java/src/service/resolve/GradleExtensionsContributor.kt index 39f4759e3b9a..c2a580779ea5 100644 --- a/plugins/gradle/java/src/service/resolve/GradleExtensionsContributor.kt +++ b/plugins/gradle/java/src/service/resolve/GradleExtensionsContributor.kt @@ -35,7 +35,7 @@ import org.jetbrains.plugins.groovy.lang.psi.patterns.groovyClosure import org.jetbrains.plugins.groovy.lang.psi.patterns.psiMethod import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil -import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_KEY +import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_TYPE_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_STRATEGY_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DelegatesToInfo import org.jetbrains.plugins.groovy.lang.resolve.getName @@ -47,35 +47,6 @@ import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessProperties */ class GradleExtensionsContributor : GradleMethodContextContributor { - override fun getDelegatesToInfo(closure: GrClosableBlock): DelegatesToInfo? { - val extensionsData = getExtensionsFor(closure) ?: return null - for (extension in extensionsData.extensions.values) { - val extensionClosure = groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, extension.name)) - if (extensionClosure.accepts(closure)) { - return DelegatesToInfo(TypesUtil.createType(extension.rootTypeFqn, closure), Closure.DELEGATE_FIRST) - } - val objectTypeFqn = extension.namedObjectTypeFqn?.let { if (it.isNotBlank()) it else null } ?: continue - val objectType = TypesUtil.createType(objectTypeFqn, closure) - val objectClosure = groovyClosure().withAncestor(2, extensionClosure) - if (objectClosure.accepts(closure)) { - return DelegatesToInfo(objectType, Closure.DELEGATE_FIRST) - } - - val objectReference = object : ElementPattern { - override fun getCondition() = null - override fun accepts(o: Any?) = false - override fun accepts(o: Any?, context: ProcessingContext): Boolean { - return o is GrExpression && o.type?.isAssignableFrom(objectType) ?: false - } - } - if (psiElement().withParent( - psiElement().withFirstChild(objectReference)).accepts(closure)) { - return DelegatesToInfo(objectType, Closure.DELEGATE_FIRST) - } - } - return null - } - override fun process(methodCallInfo: MutableList, processor: PsiScopeProcessor, state: ResolveState, @@ -109,15 +80,6 @@ class GradleExtensionsContributor : GradleMethodContextContributor { } } - extensionsData.extensions[name]?.let { - if (!processExtensionMethodProperty(processor, state, place, it)) return false - } - - for (extension in extensionsData.extensions.values) { - if (!processExtension(processor, state, place, extension)) return false - if (name == extension.name) break - } - if (place.getUserData(RESOLVED_CODE).let { it == null || !it }) { if (psiElement().withAncestor(2, groovyClosure().with(object : PatternCondition("withDelegatesToInfo") { override fun accepts(t: GrClosableBlock, context: ProcessingContext?): Boolean { @@ -144,7 +106,7 @@ class GradleExtensionsContributor : GradleMethodContextContributor { addOptionalParameter("args", JAVA_UTIL_MAP) } val closureParam = addAndGetOptionalParameter("configuration", GROOVY_LANG_CLOSURE) - closureParam.putUserData(DELEGATES_TO_KEY, it.typeFqn) + closureParam.putUserData(DELEGATES_TO_TYPE_KEY, it.typeFqn) closureParam.putUserData(DELEGATES_TO_STRATEGY_KEY, Closure.OWNER_FIRST) } if (!processor.execute(methodBuilder, state)) return false @@ -268,41 +230,6 @@ class GradleExtensionsContributor : GradleMethodContextContributor { } } -private fun processExtensionMethodProperty(processor: PsiScopeProcessor, - state: ResolveState, - place: PsiElement, - extension: GradleExtension): Boolean { - val processMethods = processor.shouldProcessMethods() - val processProperties = processor.shouldProcessProperties() - if (!processMethods && !processProperties) { - return true - } - - place.putUserData(RESOLVED_CODE, true) - - val resolveScope = place.resolveScope - val javaPsiFacade = JavaPsiFacade.getInstance(place.project) - val type = javaPsiFacade.elementFactory.createTypeByFQClassName(extension.rootTypeFqn, resolveScope) - - if (processMethods) { - val extensionMethod = GrLightMethodBuilder(place.manager, extension.name).apply { - containingClass = javaPsiFacade.findClass(GRADLE_API_PROJECT, resolveScope) - returnType = type - addParameter("configuration", GROOVY_LANG_CLOSURE) - } - if (!processor.execute(extensionMethod, state)) { - return false - } - } - if (processProperties) { - val extensionProperty = GradleExtensionProperty(extension.name, type, place) - if (!processor.execute(extensionProperty, state)) { - return false - } - } - return true -} - fun processExtension(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement, diff --git a/plugins/gradle/java/src/service/resolve/GradleIdeaSettingsContributor.kt b/plugins/gradle/java/src/service/resolve/GradleIdeaSettingsContributor.kt index f773c5481f57..112074d41565 100644 --- a/plugins/gradle/java/src/service/resolve/GradleIdeaSettingsContributor.kt +++ b/plugins/gradle/java/src/service/resolve/GradleIdeaSettingsContributor.kt @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.gradle.service.resolve import com.intellij.openapi.externalSystem.service.project.settings.ConfigurationDataService @@ -12,7 +12,7 @@ import groovy.lang.Closure import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames -import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_KEY +import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_TYPE_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_STRATEGY_KEY import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMethods @@ -49,7 +49,7 @@ class GradleIdeaSettingsContributor : GradleMethodContextContributor { containingClass = ideaProjectClass returnType = projectSettingsType addAndGetParameter("configuration", GroovyCommonClassNames.GROOVY_LANG_CLOSURE).apply { - putUserData(DELEGATES_TO_KEY, PROJECT_SETTINGS_FQN) + putUserData(DELEGATES_TO_TYPE_KEY, PROJECT_SETTINGS_FQN) putUserData(DELEGATES_TO_STRATEGY_KEY, Closure.DELEGATE_FIRST) } } @@ -66,7 +66,7 @@ class GradleIdeaSettingsContributor : GradleMethodContextContributor { containingClass = ideaModuleClass returnType = moduleSettingsType addAndGetParameter("configuration", GroovyCommonClassNames.GROOVY_LANG_CLOSURE).apply { - putUserData(DELEGATES_TO_KEY, MODULE_SETTINGS_FQN) + putUserData(DELEGATES_TO_TYPE_KEY, MODULE_SETTINGS_FQN) putUserData(DELEGATES_TO_STRATEGY_KEY, Closure.DELEGATE_FIRST) } } diff --git a/plugins/gradle/java/src/service/resolve/GradleMiscContributor.kt b/plugins/gradle/java/src/service/resolve/GradleMiscContributor.kt index 6a8268ed37d5..abd4f4e70b4e 100644 --- a/plugins/gradle/java/src/service/resolve/GradleMiscContributor.kt +++ b/plugins/gradle/java/src/service/resolve/GradleMiscContributor.kt @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.gradle.service.resolve import com.intellij.patterns.PsiJavaPatterns.psiElement @@ -21,7 +21,7 @@ import org.jetbrains.plugins.groovy.lang.psi.patterns.groovyClosure import org.jetbrains.plugins.groovy.lang.psi.patterns.psiMethod import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil -import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_KEY +import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_TYPE_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DelegatesToInfo /** @@ -91,7 +91,7 @@ class GradleMiscContributor : GradleMethodContextContributor { containingClass = pluginsDependenciesClass returnType = returnClass } - methodBuilder.addAndGetParameter("configuration", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, pluginDependenciesSpecFqn) + methodBuilder.addAndGetParameter("configuration", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, pluginDependenciesSpecFqn) place.putUserData(RESOLVED_CODE, true) if (!processor.execute(methodBuilder, state)) return false } diff --git a/plugins/gradle/java/src/service/resolve/GradleNamedDomainCollectionContributor.kt b/plugins/gradle/java/src/service/resolve/GradleNamedDomainCollectionContributor.kt new file mode 100644 index 000000000000..4c3b68d69299 --- /dev/null +++ b/plugins/gradle/java/src/service/resolve/GradleNamedDomainCollectionContributor.kt @@ -0,0 +1,58 @@ +// Copyright 2000-2019 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. +package org.jetbrains.plugins.gradle.service.resolve + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiType +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.psi.util.PsiUtil.substituteTypeParameter +import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_NAMED_DOMAIN_OBJECT_CONTAINER +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil.createType +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE +import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor +import org.jetbrains.plugins.groovy.lang.resolve.getName +import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMethods +import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessProperties + +class GradleNamedDomainCollectionContributor : NonCodeMembersContributor() { + + override fun getParentClassName(): String? = GRADLE_API_NAMED_DOMAIN_OBJECT_CONTAINER + + override fun processDynamicElements(qualifierType: PsiType, + clazz: PsiClass?, + processor: PsiScopeProcessor, + place: PsiElement, + state: ResolveState) { + if (clazz == null) return + if (state[DELEGATED_TYPE] == true) return + + val domainObjectName = processor.getName(state) ?: return // don't complete anything because we don't know what is in container + val processProperties = processor.shouldProcessProperties() + val processMethods = processor.shouldProcessMethods() + if (!processProperties && !processMethods) { + return + } + val domainObjectType = substituteTypeParameter(qualifierType, GRADLE_API_NAMED_DOMAIN_OBJECT_CONTAINER, 0, false) ?: return + + val containingFile = place.containingFile + val manager = containingFile.manager + + if (processProperties) { + val property = GradleDomainObjectProperty(domainObjectName, domainObjectType, containingFile) + if (!processor.execute(property, state)) { + return + } + } + if (processMethods) { + val method = GrLightMethodBuilder(manager, domainObjectName).apply { + returnType = domainObjectType + addParameter("configuration", createType(GROOVY_LANG_CLOSURE, containingFile)) + } + if (!processor.execute(method, state)) { + return + } + } + } +} diff --git a/plugins/gradle/java/src/service/resolve/GradleNonCodeMembersContributor.kt b/plugins/gradle/java/src/service/resolve/GradleNonCodeMembersContributor.kt index fb8cbb410b03..450aab62ffe1 100644 --- a/plugins/gradle/java/src/service/resolve/GradleNonCodeMembersContributor.kt +++ b/plugins/gradle/java/src/service/resolve/GradleNonCodeMembersContributor.kt @@ -27,7 +27,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightVariable import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil -import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_KEY +import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_TYPE_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_STRATEGY_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.getDelegatesToInfo import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessProperties @@ -92,63 +92,6 @@ class GradleNonCodeMembersContributor : NonCodeMembersContributor() { if (!shouldSkipDeclarationsAndSetters(aClass.qualifiedName)) { processDeclarations(aClass, processor, state, place) } - if (state[DELEGATED_TYPE] == true) return - val propCandidate = place.references.singleOrNull()?.canonicalText ?: return - val domainObjectType = (qualifierType.superTypes.firstOrNull { it is PsiClassType } as? PsiClassType)?.parameters?.singleOrNull() - ?: return - if (!InheritanceUtil.isInheritor(qualifierType, GRADLE_API_NAMED_DOMAIN_OBJECT_CONTAINER)) return - - val classHint = processor.getHint(com.intellij.psi.scope.ElementClassHint.KEY) - val shouldProcessMethods = ResolveUtil.shouldProcessMethods(classHint) - val shouldProcessProperties = ResolveUtil.shouldProcessProperties(classHint) - if (GradleResolverUtil.canBeMethodOf(propCandidate, aClass)) return - - val domainObjectFqn = TypesUtil.getQualifiedName(domainObjectType) ?: return - val javaPsiFacade = JavaPsiFacade.getInstance(place.project) - val domainObjectPsiClass = javaPsiFacade.findClass(domainObjectFqn, place.resolveScope) ?: return - if (GradleResolverUtil.canBeMethodOf(propCandidate, domainObjectPsiClass)) return - if (GradleResolverUtil.canBeMethodOf("get" + propCandidate.capitalize(), domainObjectPsiClass)) return - if (GradleResolverUtil.canBeMethodOf("set" + propCandidate.capitalize(), domainObjectPsiClass)) return - - val closure = PsiTreeUtil.getParentOfType(place, GrClosableBlock::class.java) - val typeToDelegate = closure?.let { getDelegatesToInfo(it)?.typeToDelegate } - if (typeToDelegate != null) { - val fqNameToDelegate = TypesUtil.getQualifiedName(typeToDelegate) ?: return - val classToDelegate = javaPsiFacade.findClass(fqNameToDelegate, place.resolveScope) ?: return - if (classToDelegate !== aClass) { - val parent = place.parent - if (parent is GrMethodCall) { - if (canBeMethodOf(propCandidate, parent, typeToDelegate)) return - } - } - } - - if (!shouldProcessMethods && shouldProcessProperties && place is GrReferenceExpression && place.parent !is GrApplicationStatement) { - val variable = GrLightField(propCandidate, domainObjectFqn, place) - place.putUserData(RESOLVED_CODE, true) - if (!processor.execute(variable, state)) return - } - if (shouldProcessMethods && place is GrReferenceExpression) { - val call = PsiTreeUtil.getParentOfType(place, GrMethodCall::class.java) ?: return - val args = call.argumentList - var argsCount = GradleResolverUtil.getGrMethodArumentsCount(args) - argsCount += call.closureArguments.size - argsCount++ // Configuration name is delivered as an argument. - - // at runtime, see org.gradle.internal.metaobject.ConfigureDelegate.invokeMethod - val wrappedBase = GrLightMethodBuilder(place.manager, propCandidate).apply { - returnType = domainObjectType - containingClass = aClass - val closureParam = addAndGetOptionalParameter("configuration", GROOVY_LANG_CLOSURE) - closureParam.putUserData(DELEGATES_TO_KEY, domainObjectFqn) - closureParam.putUserData(DELEGATES_TO_STRATEGY_KEY, Closure.DELEGATE_FIRST) - - val method = aClass.findMethodsByName("create", true).firstOrNull { it.parameterList.parametersCount == argsCount } - if (method != null) navigationElement = method - } - place.putUserData(RESOLVED_CODE, true) - if (!processor.execute(wrappedBase, state)) return - } } } diff --git a/plugins/gradle/java/src/service/resolve/GradleProjectExtensionContributor.kt b/plugins/gradle/java/src/service/resolve/GradleProjectExtensionContributor.kt new file mode 100644 index 000000000000..038f96e638b2 --- /dev/null +++ b/plugins/gradle/java/src/service/resolve/GradleProjectExtensionContributor.kt @@ -0,0 +1,66 @@ +// Copyright 2000-2019 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. +package org.jetbrains.plugins.gradle.service.resolve + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiType +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_PROJECT +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil.createType +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE +import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor +import org.jetbrains.plugins.groovy.lang.resolve.getName +import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMethods +import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessProperties + +class GradleProjectExtensionContributor : NonCodeMembersContributor() { + + override fun getParentClassName(): String? = GRADLE_API_PROJECT + + override fun processDynamicElements(qualifierType: PsiType, + aClass: PsiClass?, + processor: PsiScopeProcessor, + place: PsiElement, + state: ResolveState) { + if (qualifierType !is GradleProjectAwareType) return + + val processMethods = processor.shouldProcessMethods() + val processProperties = processor.shouldProcessProperties() + if (!processMethods && !processProperties) { + return + } + + val containingFile = place.containingFile + val extensionsData = GradleExtensionsContributor.getExtensionsFor(containingFile) ?: return + + val name = processor.getName(state) + val allExtensions = extensionsData.extensions + val extensions = if (name == null) allExtensions.values else listOf(allExtensions[name] ?: return) + if (extensions.isEmpty()) return + + val factory = GroovyPsiElementFactory.getInstance(containingFile.project) + val manager = containingFile.manager + + for (extension in extensions) { + val type = factory.createTypeElement(extension.rootTypeFqn, containingFile).type + if (processProperties) { + val extensionProperty = GradleExtensionProperty(extension.name, type, containingFile) + if (!processor.execute(extensionProperty, state)) { + return + } + } + if (processMethods) { + val extensionMethod = GrLightMethodBuilder(manager, extension.name).apply { + returnType = type + addParameter("configuration", createType(GROOVY_LANG_CLOSURE, containingFile)) + } + if (!processor.execute(extensionMethod, state)) { + return + } + } + } + } +} diff --git a/plugins/gradle/java/src/service/resolve/GradleUnresolvedReferenceFilter.java b/plugins/gradle/java/src/service/resolve/GradleUnresolvedReferenceFilter.java index c1d546e9865a..65fc37afa810 100644 --- a/plugins/gradle/java/src/service/resolve/GradleUnresolvedReferenceFilter.java +++ b/plugins/gradle/java/src/service/resolve/GradleUnresolvedReferenceFilter.java @@ -1,33 +1,15 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.gradle.service.resolve; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClassType; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.PsiType; import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.gradle.settings.GradleExtensionsSettings; import org.jetbrains.plugins.groovy.extensions.GroovyUnresolvedHighlightFilter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; -import java.util.HashSet; import java.util.Set; import static com.intellij.util.containers.ContainerUtil.newHashSet; @@ -63,15 +45,6 @@ public class GradleUnresolvedReferenceFilter extends GroovyUnresolvedHighlightFi return false; } - Set toIgnore = new HashSet<>(IGNORE_SET); - GradleExtensionsSettings.GradleExtensionsData extensionsData = GradleExtensionsContributor.Companion.getExtensionsFor(expression); - if (extensionsData != null) { - for (GradleExtensionsSettings.GradleExtension extension : extensionsData.extensions.values()) { - if (StringUtil.isNotEmpty(extension.namedObjectTypeFqn)) { - toIgnore.add(extension.namedObjectTypeFqn); - } - } - } - return toIgnore.contains(TypesUtil.getQualifiedName(psiType)); + return false; } } diff --git a/plugins/gradle/java/src/service/resolve/NamedDomainObjectCollectionTypeEnhancer.java b/plugins/gradle/java/src/service/resolve/NamedDomainObjectCollectionTypeEnhancer.java deleted file mode 100644 index b25fa8cda07b..000000000000 --- a/plugins/gradle/java/src/service/resolve/NamedDomainObjectCollectionTypeEnhancer.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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. - */ -package org.jetbrains.plugins.gradle.service.resolve; - -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiType; -import com.intellij.psi.impl.source.PsiClassReferenceType; -import com.intellij.psi.util.InheritanceUtil; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.gradle.settings.GradleExtensionsSettings; -import org.jetbrains.plugins.groovy.extensions.GroovyMapContentProvider; -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.impl.GroovyPsiManager; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; -import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrReferenceTypeEnhancer; - -/** - * @author Vladislav.Soroka - */ -public class NamedDomainObjectCollectionTypeEnhancer extends GrReferenceTypeEnhancer { - @Override - public PsiType getReferenceType(GrReferenceExpression ref, @Nullable PsiElement resolved) { - if (resolved != null) return null; - - GrExpression qualifierExpression = ref.getQualifierExpression(); - if (qualifierExpression == null) return null; - - PsiType namedDomainCollectionType = GradleResolverUtil.getTypeOf(qualifierExpression); - - if (!InheritanceUtil.isInheritor(namedDomainCollectionType, GradleCommonClassNames.GRADLE_API_NAMED_DOMAIN_OBJECT_COLLECTION)) { - return null; - } - - PsiElement qResolved; - - if (qualifierExpression instanceof GrReferenceExpression) { - qResolved = ((GrReferenceExpression)qualifierExpression).resolve(); - } - else if (qualifierExpression instanceof GrMethodCall) { - qResolved = ((GrMethodCall)qualifierExpression).resolveMethod(); - } - else { - return null; - } - - String key = ref.getReferenceName(); - if (key == null) return null; - - for (GroovyMapContentProvider provider : GroovyMapContentProvider.EP_NAME.getExtensions()) { - PsiType type = provider.getValueType(qualifierExpression, qResolved, key); - if (type != null) { - return type; - } - } - - if (namedDomainCollectionType instanceof PsiClassReferenceType) { - final PsiClassReferenceType referenceType = (PsiClassReferenceType)namedDomainCollectionType; - final String fqName = TypesUtil.getQualifiedName(referenceType); - if (GradleCommonClassNames.GRADLE_API_SOURCE_SET_CONTAINER.equals(fqName)) { - final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject()); - return psiManager.createTypeByFQClassName(GradleCommonClassNames.GRADLE_API_SOURCE_SET, ref.getResolveScope()); - } - else if (GradleCommonClassNames.GRADLE_API_CONFIGURATION_CONTAINER.equals(fqName)) { - final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject()); - return psiManager.createTypeByFQClassName(GradleCommonClassNames.GRADLE_API_CONFIGURATION, ref.getResolveScope()); - } - else if (GradleCommonClassNames.GRADLE_API_TASK_CONTAINER.equals(fqName)) { - final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject()); - return psiManager.createTypeByFQClassName(GradleCommonClassNames.GRADLE_API_TASK, ref.getResolveScope()); - } - else if (GradleCommonClassNames.GRADLE_API_DISTRIBUTION_CONTAINER.equals(fqName)) { - final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject()); - return psiManager.createTypeByFQClassName(GradleCommonClassNames.GRADLE_API_DISTRIBUTION, ref.getResolveScope()); - } - else { - GradleExtensionsSettings.GradleExtensionsData extensionsData = GradleExtensionsContributor.Companion.getExtensionsFor(ref); - if (extensionsData != null) { - for (GradleExtensionsSettings.GradleExtension extension : extensionsData.extensions.values()) { - if (StringUtil.isNotEmpty(extension.namedObjectTypeFqn) && extension.rootTypeFqn.equals(fqName)) { - final GroovyPsiManager psiManager = GroovyPsiManager.getInstance(ref.getProject()); - return psiManager.createTypeByFQClassName(extension.namedObjectTypeFqn, ref.getResolveScope()); - } - } - } - } - } - - return null; - } -} diff --git a/plugins/gradle/java/testSources/dsl/GradleDistributionsTest.groovy b/plugins/gradle/java/testSources/dsl/GradleDistributionsTest.groovy index 99d644f7d138..1ab00dc66b9a 100644 --- a/plugins/gradle/java/testSources/dsl/GradleDistributionsTest.groovy +++ b/plugins/gradle/java/testSources/dsl/GradleDistributionsTest.groovy @@ -1,24 +1,29 @@ // Copyright 2000-2019 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. package org.jetbrains.plugins.gradle.dsl +import com.intellij.psi.PsiMethod import com.intellij.testFramework.RunAll import groovy.transform.CompileStatic import org.jetbrains.plugins.gradle.highlighting.GradleHighlightingBaseTest -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.util.ResolveTest +import org.jetbrains.plugins.gradle.service.resolve.GradleDomainObjectProperty +import org.jetbrains.plugins.gradle.service.resolve.GradleExtensionProperty +import org.jetbrains.plugins.groovy.util.ExpressionTest import org.junit.Test import static org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_DISTRIBUTION import static org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_FILE_COPY_SPEC @CompileStatic -class GradleDistributionsTest extends GradleHighlightingBaseTest implements ResolveTest { +class GradleDistributionsTest extends GradleHighlightingBaseTest implements ExpressionTest { @Test void distributionsTest() { importProject("apply plugin: 'distribution'") new RunAll().append { + 'distributions container'() + } append { + 'distributions call'() + } append { 'distributions closure delegate'() } append { 'distribution via unqualified property reference'() @@ -43,9 +48,26 @@ class GradleDistributionsTest extends GradleHighlightingBaseTest implements Reso @Override protected List getParentCalls() { +// return [] return super.getParentCalls() + 'buildscript' } + void 'distributions container'() { + def type = isGradleAtLeast("3.5") ? "org.gradle.api.NamedDomainObjectContainer" + : "org.gradle.api.distribution.internal.DefaultDistributionContainer" + doTest('distributions') { + referenceExpressionTest(GradleExtensionProperty, type) + } + } + + void 'distributions call'() { + def type = isGradleAtLeast("3.5") ? "org.gradle.api.NamedDomainObjectContainer" + : "org.gradle.api.distribution.internal.DefaultDistributionContainer" + doTest('distributions {}') { + methodCallTest(PsiMethod, type) + } + } + void 'distributions closure delegate'() { def type = isGradleAtLeast("3.5") ? "org.gradle.api.NamedDomainObjectContainer" : "org.gradle.api.distribution.internal.DefaultDistributionContainer" @@ -56,17 +78,13 @@ class GradleDistributionsTest extends GradleHighlightingBaseTest implements Reso void 'distribution via unqualified property reference'() { doTest('distributions { foo }') { - def ref = elementUnderCaret(GrReferenceExpression) - assert ref.resolve() != null - assert ref.type.equalsToText("org.gradle.api.distribution.internal.DefaultDistribution") + referenceExpressionTest(GradleDomainObjectProperty, GRADLE_API_DISTRIBUTION) } } void 'distribution via unqualified method call'() { doTest('distributions { foo {} }') { - def call = elementUnderCaret(GrMethodCall) - assert call.resolveMethod() != null - assert call.type.equalsToText(GRADLE_API_DISTRIBUTION) + methodCallTest(PsiMethod, GRADLE_API_DISTRIBUTION) } } @@ -78,40 +96,32 @@ class GradleDistributionsTest extends GradleHighlightingBaseTest implements Reso void 'distribution member via unqualified method call closure delegate'() { doTest('distributions { foo { getBaseName() } }') { - def call = elementUnderCaret(GrMethodCall) - def method = call.resolveMethod() - assert method != null + def method = resolveMethodTest(PsiMethod) assert method.containingClass.qualifiedName == GRADLE_API_DISTRIBUTION } } void 'distribution via qualified property reference'() { - doTest('distributions { foo }; distributions.foo') { - def ref = elementUnderCaret(GrReferenceExpression) - assert ref.resolve() != null - assert ref.type.equalsToText(GRADLE_API_DISTRIBUTION) + doTest('distributions.foo') { + referenceExpressionTest(GradleDomainObjectProperty, GRADLE_API_DISTRIBUTION) } } void 'distribution via qualified method call'() { - doTest('distributions { foo }; distributions.foo {}') { - def call = elementUnderCaret(GrMethodCall) - assert call.resolveMethod() != null - assert call.type.equalsToText(GRADLE_API_DISTRIBUTION) + doTest('distributions.foo {}') { + methodCallTest(PsiMethod, GRADLE_API_DISTRIBUTION) } } void 'distribution closure delegate in qualified method call'() { - doTest('distributions { foo }; distributions.foo { }') { + doTest('distributions.foo { }') { closureDelegateTest(GRADLE_API_DISTRIBUTION, 1) } } void 'distribution member via qualified method call closure delegate'() { - doTest('distributions { foo }; distributions.foo { getBaseName() }') { - def call = elementUnderCaret(GrMethodCall) - def method = call.resolveMethod() - assert method != null + doTest('distributions.foo { getBaseName() }') { + def method = resolveMethodTest(PsiMethod) assert method.containingClass.qualifiedName == GRADLE_API_DISTRIBUTION } } diff --git a/plugins/gradle/java/testSources/dsl/GradleTasksTest.groovy b/plugins/gradle/java/testSources/dsl/GradleTasksTest.groovy index 57c7720f7312..4ede26024249 100644 --- a/plugins/gradle/java/testSources/dsl/GradleTasksTest.groovy +++ b/plugins/gradle/java/testSources/dsl/GradleTasksTest.groovy @@ -1,18 +1,18 @@ // Copyright 2000-2019 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. package org.jetbrains.plugins.gradle.dsl +import com.intellij.psi.PsiMethod import com.intellij.testFramework.RunAll import groovy.transform.CompileStatic import org.jetbrains.plugins.gradle.highlighting.GradleHighlightingBaseTest -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression -import org.jetbrains.plugins.groovy.lang.resolve.api.GroovyProperty -import org.jetbrains.plugins.groovy.util.ResolveTest +import org.jetbrains.plugins.gradle.service.resolve.GradleTaskProperty +import org.jetbrains.plugins.groovy.util.ExpressionTest import org.junit.Test import static org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.* @CompileStatic -class GradleTasksTest extends GradleHighlightingBaseTest implements ResolveTest { +class GradleTasksTest extends GradleHighlightingBaseTest implements ExpressionTest { @Override protected List getParentCalls() { @@ -24,6 +24,8 @@ class GradleTasksTest extends GradleHighlightingBaseTest implements ResolveTest importProject("apply plugin:'java'") new RunAll().append { 'task via script'() + } append { + 'task container vs task'() } append { 'task via TaskContainer'() } append { @@ -41,6 +43,12 @@ class GradleTasksTest extends GradleHighlightingBaseTest implements ResolveTest } } + void 'task container vs task'() { + doTest('tasks') { + referenceExpressionTest(PsiMethod, GRADLE_API_TASK_CONTAINER) + } + } + void 'task via TaskContainer'() { doTest('tasks.tasks') { testTask('tasks', GRADLE_API_TASKS_DIAGNOSTICS_TASK_REPORT_TASK) @@ -66,11 +74,7 @@ class GradleTasksTest extends GradleHighlightingBaseTest implements ResolveTest } private void testTask(String name, String type) { - def expression = elementUnderCaret(GrReferenceExpression) - def results = expression.resolve(false) - assert results.size() == 1 - def property = assertInstanceOf(results[0].element, GroovyProperty) + def property = referenceExpressionTest(GradleTaskProperty, type) assert property.name == name - assert expression.type.equalsToText(type) } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleBuildScriptErrorParser.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleBuildScriptErrorParser.kt index 0d4ea5a1f41b..e3dabc949914 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleBuildScriptErrorParser.kt +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleBuildScriptErrorParser.kt @@ -37,7 +37,7 @@ class GradleBuildScriptErrorParser : BuildOutputParser { parentId = reason.substringAfter("Execution failed for task '").substringBefore("'.") } else { - parentId = reader.buildId + parentId = reader.parentEventId } description.appendln(reason) loop@ while (true) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleOutputDispatcherFactory.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleOutputDispatcherFactory.kt index 9d3092cdaf21..837948140c8a 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleOutputDispatcherFactory.kt +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleOutputDispatcherFactory.kt @@ -7,7 +7,6 @@ import com.intellij.build.events.StartEvent import com.intellij.build.output.BuildOutputInstantReaderImpl import com.intellij.build.output.BuildOutputParser import com.intellij.build.output.LineProcessor -import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.externalSystem.service.execution.ExternalSystemOutputDispatcherFactory import com.intellij.openapi.externalSystem.service.execution.ExternalSystemOutputMessageDispatcher import org.gradle.api.logging.LogLevel @@ -31,13 +30,11 @@ class GradleOutputDispatcherFactory : ExternalSystemOutputDispatcherFactory { private val lineProcessor: LineProcessor private val myRootReader: BuildOutputInstantReaderImpl private var myCurrentReader: BuildOutputInstantReaderImpl - private val tasksOutputReaders: MutableMap - private val tasksEventIds: MutableMap + private val tasksOutputReaders = mutableMapOf() + private val tasksEventIds = mutableMapOf() init { - tasksOutputReaders = mutableMapOf() - tasksEventIds = mutableMapOf() - myRootReader = BuildOutputInstantReaderImpl(buildId, BuildProgressListener() { + myRootReader = BuildOutputInstantReaderImpl(buildId, BuildProgressListener { var buildEvent = it val parentId = buildEvent.parentId if (parentId != buildId && parentId is String) { @@ -67,16 +64,10 @@ class GradleOutputDispatcherFactory : ExternalSystemOutputDispatcherFactory { override fun onEvent(event: BuildEvent) { myBuildProgressListener.onEvent(event) if (event is StartEvent && event.parentId == buildId) { - val taskReader = tasksOutputReaders[event.message] - if (taskReader != null) { // multiple invocations of the same task during the build session - taskReader.close() - } + tasksOutputReaders[event.message]?.close() // multiple invocations of the same task during the build session val parentEventId = event.id - tasksOutputReaders[event.message] = BuildOutputInstantReaderImpl(buildId, BuildProgressListener() { - val buildEvent = if (it.parentId == buildId) BuildEventInvocationHandler.wrap(it, parentEventId) else it - myBuildProgressListener.onEvent(buildEvent) - }, parsers) + tasksOutputReaders[event.message] = BuildOutputInstantReaderImpl(parentEventId, myBuildProgressListener, parsers) tasksEventIds[event.message] = parentEventId } } @@ -134,17 +125,13 @@ class GradleOutputDispatcherFactory : ExternalSystemOutputDispatcherFactory { companion object { fun wrap(buildEvent: BuildEvent, parentEventId: Any): BuildEvent { - val classLoader = buildEvent.javaClass.getClassLoader() - val interfaces = buildEvent.javaClass.getInterfaces() + val classLoader = buildEvent.javaClass.classLoader + val interfaces = buildEvent.javaClass.interfaces val invocationHandler = BuildEventInvocationHandler(buildEvent, parentEventId) return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler) as BuildEvent } } } } - - companion object { - private val LOG = logger() - } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleOutputParserProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleOutputParserProvider.java index 92388a756e7a..73c8f112ac5d 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleOutputParserProvider.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleOutputParserProvider.java @@ -2,14 +2,15 @@ package org.jetbrains.plugins.gradle.execution.build.output; import com.intellij.build.output.BuildOutputParser; +import com.intellij.build.output.JavacOutputParser; +import com.intellij.build.output.KotlincOutputParser; import com.intellij.openapi.externalSystem.model.ProjectSystemId; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTask; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType; import com.intellij.openapi.externalSystem.service.execution.ExternalSystemOutputParserProvider; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.SmartList; import org.jetbrains.plugins.gradle.util.GradleConstants; -import java.util.Collections; import java.util.List; /** @@ -23,11 +24,13 @@ public class GradleOutputParserProvider implements ExternalSystemOutputParserPro @Override public List getBuildOutputParsers(ExternalSystemTask task) { + List parsers = new SmartList<>(); if (task.getId().getType().equals(ExternalSystemTaskType.RESOLVE_PROJECT)) { - return ContainerUtil.list(new GradleSyncOutputParser(), new GradleBuildScriptErrorParser()); - } - else { - return ContainerUtil.list(new GradleBuildScriptErrorParser()); + parsers.add(new GradleSyncOutputParser()); } + parsers.add(new GradleBuildScriptErrorParser()); + parsers.add(new JavacOutputParser()); + parsers.add(new KotlincOutputParser()); + return parsers; } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleSyncOutputParser.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleSyncOutputParser.java index a86282414c4a..dc26a46ef067 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleSyncOutputParser.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/build/output/GradleSyncOutputParser.java @@ -6,6 +6,7 @@ import com.intellij.build.events.MessageEvent; import com.intellij.build.events.impl.MessageEventImpl; import com.intellij.build.output.BuildOutputInstantReader; import com.intellij.build.output.BuildOutputParser; +import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; @@ -18,7 +19,7 @@ public class GradleSyncOutputParser implements BuildOutputParser { private static final String WARNING_PREFIX = "[sync warning]"; @Override - public boolean parse(String line, BuildOutputInstantReader reader, Consumer messageConsumer) { + public boolean parse(@NotNull String line, @NotNull BuildOutputInstantReader reader, @NotNull Consumer messageConsumer) { MessageEvent.Kind kind = MessageEvent.Kind.ERROR; String prefix = ERROR_PREFIX; int prefixIndex = line.indexOf(ERROR_PREFIX); @@ -32,7 +33,7 @@ public class GradleSyncOutputParser implements BuildOutputParser { } String text = line.substring(prefixIndex + prefix.length()).trim(); - messageConsumer.accept(new MessageEventImpl(reader.getBuildId(), kind, null, text, text)); + messageConsumer.accept(new MessageEventImpl(reader.getParentEventId(), kind, null, text, text)); return true; } } 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 3d0b2c5c58ad..16f91f2a05d8 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java @@ -43,6 +43,35 @@ import static com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil.get */ public class GradleFoldersImportingTest extends GradleImportingTestCase { + @Test + public void testUnsupportedTypesInDsl() throws Exception { + importProject( + new GradleBuildScriptBuilderEx().addPostfix( + "import org.gradle.api.internal.FactoryNamedDomainObjectContainer;", + "import org.gradle.internal.reflect.Instantiator;", + "class MyObj implements Named {", + " String myName;", + " public MyObj(String name) {", + " myName = namse", + " }", + " ", + " public String getName() {", + " return myName", + " }", + "}", + "project.extensions.create(", + " \"sourceSets\",", + " FactoryNamedDomainObjectContainer,", + " MyObj,", + " services.get(Instantiator),", + " {action -> }", + " ) ", + "sourceSets {", + " println \"Hello World!\"", + "}" + ).generate()); + } + @Test public void testBaseJavaProject() throws Exception { getCurrentExternalProjectSettings().setDelegatedBuild(ThreeState.NO); diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalTestsModelBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalTestsModelBuilderImpl.groovy index e05b300b597f..eb12c6afaf58 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalTestsModelBuilderImpl.groovy +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalTestsModelBuilderImpl.groovy @@ -22,10 +22,16 @@ class ExternalTestsModelBuilderImpl implements ModelBuilderService { @Override Object buildAll(String modelName, Project project) { def defaultTestsModel = new DefaultExternalTestsModel() - defaultTestsModel.sourceTestMappings = getMapping(project) + if (javaPluginIsApplied(project)) { + defaultTestsModel.sourceTestMappings = getMapping(project) + } return defaultTestsModel } + private static boolean javaPluginIsApplied(Project project) { + return project.pluginManager.findPlugin('java-base') != null + } + private static List getMapping(Project project) { def taskToClassesDirs = new LinkedHashMap>() for (def task : project.tasks) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonBuilderContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonBuilderContributor.java index 4a2ecb5700c5..9f16a314413e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonBuilderContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonBuilderContributor.java @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.builder; import com.intellij.psi.PsiClass; @@ -14,7 +14,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder import static com.intellij.psi.CommonClassNames.JAVA_UTIL_MAP; import static org.jetbrains.plugins.groovy.builder.JsonDelegateContributor.DELEGATE_FQN; import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE; -import static org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.GrDelegatesToUtilKt.DELEGATES_TO_KEY; +import static org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.GrDelegatesToUtilKt.DELEGATES_TO_TYPE_KEY; public class JsonBuilderContributor extends BuilderMethodsContributor { @@ -41,7 +41,7 @@ public class JsonBuilderContributor extends BuilderMethodsContributor { // (Closure) method = createMethod(name, clazz, place); - method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); + method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, DELEGATE_FQN); if (!processor.process(method)) return false; // (Map) @@ -52,19 +52,19 @@ public class JsonBuilderContributor extends BuilderMethodsContributor { // (Map, Closure) method = createMethod(name, clazz, place); method.addParameter("map", JAVA_UTIL_MAP); - method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); + method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, DELEGATE_FQN); if (!processor.process(method)) return false; // (Iterable, Closure) method = createMethod(name, clazz, place); method.addParameter("value", TypesUtil.createIterableType(place, null)); - method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); + method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, DELEGATE_FQN); if (!processor.process(method)) return false; // (Object[], Closure) method = createMethod(name, clazz, place); method.addParameter("value", TypesUtil.getJavaLangObject(place).createArrayType()); - method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); + method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, DELEGATE_FQN); return processor.process(method); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonDelegateContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonDelegateContributor.java index f46bd5804330..adb39b97f3b3 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonDelegateContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/JsonDelegateContributor.java @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.builder; import com.intellij.psi.*; @@ -9,7 +9,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder; import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE; -import static org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.GrDelegatesToUtilKt.DELEGATES_TO_KEY; +import static org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.GrDelegatesToUtilKt.DELEGATES_TO_TYPE_KEY; public class JsonDelegateContributor extends BuilderMethodsContributor { @@ -48,7 +48,7 @@ public class JsonDelegateContributor extends BuilderMethodsContributor { method = createMethod(name, clazz, place); genericType = facade.getElementFactory().createType(method.addTypeParameter("T")); method.addParameter("values", genericType.createArrayType()); - method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); + method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, DELEGATE_FQN); method.setReturnType(TypesUtil.createListType(place, genericType)); if (!processor.process(method)) return false; @@ -56,7 +56,7 @@ public class JsonDelegateContributor extends BuilderMethodsContributor { method = createMethod(name, clazz, place); genericType = facade.getElementFactory().createType(method.addTypeParameter("T")); method.addParameter("values", TypesUtil.createIterableType(place, genericType)); - method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, DELEGATE_FQN); + method.addAndGetParameter("c", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, DELEGATE_FQN); method.setReturnType(TypesUtil.createListType(place, genericType)); if (!processor.process(method)) return false; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderContributor.java index 8e5da3b1b2cc..33258685ad58 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderContributor.java @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.builder; import com.intellij.psi.PsiClass; @@ -15,7 +15,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter; import static com.intellij.psi.CommonClassNames.JAVA_UTIL_MAP; import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE; -import static org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.GrDelegatesToUtilKt.DELEGATES_TO_KEY; +import static org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.GrDelegatesToUtilKt.DELEGATES_TO_TYPE_KEY; import static org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.GrDelegatesToUtilKt.DELEGATES_TO_STRATEGY_KEY; public class StreamingJsonBuilderContributor extends BuilderMethodsContributor { @@ -89,7 +89,7 @@ public class StreamingJsonBuilderContributor extends BuilderMethodsContributor { protected void addClosureParameter(GrLightMethodBuilder method) { GrLightParameter closureParam = method.addAndGetParameter("closure", GROOVY_LANG_CLOSURE); - closureParam.putUserData(DELEGATES_TO_KEY, getDelegateClassName()); + closureParam.putUserData(DELEGATES_TO_TYPE_KEY, getDelegateClassName()); closureParam.putUserData(DELEGATES_TO_STRATEGY_KEY, Closure.OWNER_FIRST); } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderNonCodeMemberContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderNonCodeMemberContributor.java index 1ed731538b1f..dc1e0f146034 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderNonCodeMemberContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/builder/XmlMarkupBuilderNonCodeMemberContributor.java @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.builder; import com.intellij.psi.PsiClass; @@ -12,7 +12,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder import static com.intellij.psi.CommonClassNames.*; import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE; -import static org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.GrDelegatesToUtilKt.DELEGATES_TO_KEY; +import static org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.GrDelegatesToUtilKt.DELEGATES_TO_TYPE_KEY; public class XmlMarkupBuilderNonCodeMemberContributor extends BuilderMethodsContributor { @@ -39,19 +39,19 @@ public class XmlMarkupBuilderNonCodeMemberContributor extends BuilderMethodsCont // (Closure) res = createMethod(name, clazz, place); - res.addAndGetParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, FQN); + res.addAndGetParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, FQN); if (!processor.process(res)) return false; // (Object, Closure) res = createMethod(name, clazz, place); res.addParameter("value", JAVA_LANG_OBJECT); - res.addAndGetParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, FQN); + res.addAndGetParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, FQN); if (!processor.process(res)) return false; // (Map, Closure) res = createMethod(name, clazz, place); res.addParameter("attributes", JAVA_UTIL_MAP); - res.addAndGetParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, FQN); + res.addAndGetParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, FQN); if (!processor.process(res)) return false; // (Map) @@ -60,7 +60,7 @@ public class XmlMarkupBuilderNonCodeMemberContributor extends BuilderMethodsCont res = createMethod(name, clazz, place); res.addParameter("attributes", JAVA_UTIL_MAP); res.addOptionalParameter("value", JAVA_LANG_OBJECT); - res.addAndGetOptionalParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, FQN); + res.addAndGetOptionalParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, FQN); for (GrReflectedMethod method : res.getReflectedMethods()) { if (!processor.process(method)) return false; } @@ -71,7 +71,7 @@ public class XmlMarkupBuilderNonCodeMemberContributor extends BuilderMethodsCont res = createMethod(name, clazz, place); res.addParameter("value", JAVA_LANG_OBJECT); res.addOptionalParameter("attributes", JAVA_UTIL_MAP); - res.addAndGetOptionalParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_KEY, FQN); + res.addAndGetOptionalParameter("body", GROOVY_LANG_CLOSURE).putUserData(DELEGATES_TO_TYPE_KEY, FQN); for (GrReflectedMethod method : res.getReflectedMethods()) { if (!processor.process(method)) return false; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java index b8907e26f629..1a89577d2573 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java @@ -12,7 +12,6 @@ import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ConcurrencyUtil; -import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -30,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; /** * @author ven @@ -131,7 +131,7 @@ public class GroovyPsiManager { PsiType type = map.get(key); if (type == null) { RecursionGuard.StackStamp stamp = RecursionManager.markStack(); - type = calculator.fun(key); + type = calculator.apply(key); if (type == null) { type = UNKNOWN_TYPE; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/InferenceContext.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/InferenceContext.java index 8ed4f48ff228..b91643865cba 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/InferenceContext.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/InferenceContext.java @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.psi.impl; import com.intellij.openapi.util.Computable; @@ -8,7 +8,6 @@ import com.intellij.psi.PsiType; import com.intellij.psi.ResolveResult; import com.intellij.psi.impl.source.resolve.ResolveCache.AbstractResolver; import com.intellij.psi.impl.source.resolve.ResolveCache.PolyVariantResolver; -import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; @@ -19,6 +18,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.GroovyResolver; import java.util.Collection; import java.util.Collections; +import java.util.function.Function; /** * @author peter diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PartialContext.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PartialContext.kt index 75d9c4579b21..2472419445b6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PartialContext.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PartialContext.kt @@ -5,13 +5,13 @@ import com.intellij.openapi.util.Computable import com.intellij.psi.PsiReference import com.intellij.psi.PsiType import com.intellij.psi.impl.source.resolve.ResolveCache.AbstractResolver -import com.intellij.util.Function import gnu.trove.THashMap import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression import org.jetbrains.plugins.groovy.lang.psi.controlFlow.VariableDescriptor import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.createDescriptor import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAType +import java.util.function.Function class PartialContext(private val types: Map) : InferenceContext { @@ -49,7 +49,7 @@ class PartialContext(private val types: Map) : Infe override fun getExpressionType(element: T, calculator: Function): PsiType? { return doGetCachedValue(Pair(element, "type")) { - calculator.`fun`(element) + calculator.apply(element) } } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/TopInferenceContext.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/TopInferenceContext.kt index c1843b7ddd75..6a0cd5d28e96 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/TopInferenceContext.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/TopInferenceContext.kt @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.psi.impl import com.intellij.openapi.util.Computable @@ -9,10 +9,10 @@ import com.intellij.psi.impl.source.resolve.ResolveCache.AbstractResolver import com.intellij.psi.util.CachedValueProvider.Result import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import com.intellij.util.Function import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper +import java.util.function.Function class TopInferenceContext : InferenceContext { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java index 975153219414..55157fdd8c8b 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java @@ -9,9 +9,7 @@ import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; -import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.NullableFunction; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; @@ -32,6 +30,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.MethodTypeInferencer; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import static com.intellij.psi.util.CachedValueProvider.Result.create; import static org.jetbrains.plugins.groovy.lang.psi.impl.FunctionalExpressionsKt.*; @@ -174,7 +173,7 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock } private static final Function ourTypesCalculator = - (NullableFunction)block -> GroovyPsiManager.inferType(block, new MethodTypeInferencer(block)); + block -> GroovyPsiManager.inferType(block, new MethodTypeInferencer(block)); @Override @Nullable diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/ClassUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/ClassUtil.java index c74edafc207e..60db0bd56880 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/ClassUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/ClassUtil.java @@ -1,13 +1,13 @@ -// Copyright 2000-2017 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-2019 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. package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; import com.intellij.psi.PsiClass; import com.intellij.psi.util.InheritanceUtil; -import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.util.LightCacheKey; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -17,7 +17,7 @@ public class ClassUtil { public static Map getSuperClassesWithCache(@NotNull PsiClass aClass) { Map superClassNames = PARENT_CACHE_KEY.getCachedValue(aClass); if (superClassNames == null) { - Set superClasses = new THashSet<>(); + Set superClasses = new LinkedHashSet<>(); superClasses.add(aClass); InheritanceUtil.getSuperClasses(aClass, superClasses, true); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java index 1ac0c2ceb824..56fca9fb9728 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java @@ -5,7 +5,6 @@ import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import com.intellij.psi.tree.IElementType; -import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; @@ -20,6 +19,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.references.GrOperatorReference; import org.jetbrains.plugins.groovy.util.SafePublicationClearableLazyValue; import java.util.Objects; +import java.util.function.Function; import static org.jetbrains.plugins.groovy.lang.psi.GroovyTokenSets.ASSIGNMENTS; import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil.getLeastUpperBoundNullable; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java index 16dd29ab281a..eb933409d949 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/members/GrMethodBaseImpl.java @@ -15,7 +15,6 @@ import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; import com.intellij.ui.RowIcon; -import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; @@ -62,6 +61,7 @@ import javax.swing.*; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.function.Function; import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.shouldProcessLocals; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java index d5edf2e7d13e..5867a4b8af42 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/ClosureSyntheticParameter.java @@ -1,18 +1,4 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.lang.psi.impl.synthetic; import com.intellij.navigation.NavigationItem; @@ -21,7 +7,6 @@ import com.intellij.psi.PsiIntersectionType; import com.intellij.psi.PsiType; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; -import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,6 +17,8 @@ import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrVariableEnhancer; +import java.util.function.Function; + /** * @author ven */ diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/SimpleGroovyProperty.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/SimpleGroovyProperty.kt new file mode 100644 index 000000000000..a0ff62cb15c4 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/SimpleGroovyProperty.kt @@ -0,0 +1,11 @@ +// Copyright 2000-2019 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. +package org.jetbrains.plugins.groovy.lang.resolve.api + +import com.intellij.ide.presentation.Presentation +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiType + +open class SimpleGroovyProperty(name: String, private val type: PsiType?, context: PsiElement) : GroovyPropertyBase(name, context) { + + final override fun getPropertyType(): PsiType? = type +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/delegatesTo/DefaultDelegatesToProvider.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/delegatesTo/DefaultDelegatesToProvider.kt index 6f5c34a18acf..aa0fc3c71a0d 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/delegatesTo/DefaultDelegatesToProvider.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/delegatesTo/DefaultDelegatesToProvider.kt @@ -42,7 +42,11 @@ class DefaultDelegatesToProvider : GrDelegatesToProvider { val parameterList = method.parameterList val parameter = findParameter(parameterList, expression, map) ?: return null - val delegateFqnData = parameter.getUserData(DELEGATES_TO_KEY) + parameter.getUserData(DELEGATES_TO_KEY)?.let { + return it + } + + val delegateFqnData = parameter.getUserData(DELEGATES_TO_TYPE_KEY) val strategyData = parameter.getUserData(DELEGATES_TO_STRATEGY_KEY) if (delegateFqnData != null) { return DelegatesToInfo( diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/delegatesTo/grDelegatesToUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/delegatesTo/grDelegatesToUtil.kt index 03ed50da15de..aced2344a5db 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/delegatesTo/grDelegatesToUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/delegatesTo/grDelegatesToUtil.kt @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve.delegatesTo import com.intellij.openapi.util.Key @@ -11,8 +11,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GrFunctionalExpression import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall -@JvmField val DELEGATES_TO_KEY: Key = Key.create("groovy.closure.delegatesTo.type") -@JvmField val DELEGATES_TO_STRATEGY_KEY: Key = Key.create("groovy.closure.delegatesTo.strategy") +@JvmField +val DELEGATES_TO_KEY: Key = Key.create("groovy.closure.delegatesTo") +@JvmField +val DELEGATES_TO_TYPE_KEY: Key = Key.create("groovy.closure.delegatesTo.type") +@JvmField +val DELEGATES_TO_STRATEGY_KEY: Key = Key.create("groovy.closure.delegatesTo.strategy") val defaultDelegatesToInfo: DelegatesToInfo = DelegatesToInfo(null, Closure.OWNER_ONLY) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt index 31b871b2b0af..cd451c60df9c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt @@ -1,4 +1,4 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.ext.logback import com.intellij.openapi.util.Key @@ -19,7 +19,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil -import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_KEY +import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_TYPE_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_STRATEGY_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.getContainingCall import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMethods @@ -108,7 +108,7 @@ class LogbackDelegateMemberContributor : NonCodeMembersContributor() { wrappedBase.copy().apply { addParameter("clazz", classType) addAndGetOptionalParameter("configuration", GROOVY_LANG_CLOSURE).apply { - putUserData(DELEGATES_TO_KEY, componentDelegateFqn) + putUserData(DELEGATES_TO_TYPE_KEY, componentDelegateFqn) putUserData(DELEGATES_TO_STRATEGY_KEY, DELEGATE_FIRST) } }.let { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GrMainCompletionProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GrMainCompletionProvider.java index f415f5022c16..82d28f4b63af 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GrMainCompletionProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GrMainCompletionProvider.java @@ -356,7 +356,7 @@ public class GrMainCompletionProvider extends CompletionProvider overloads, + protected LookupElement createLookupElement(@NotNull List overloads, @NotNull PsiClass containingClass, boolean shouldImport) { shouldImport |= originalPosition != null && PsiTreeUtil.isAncestor(containingClass, originalPosition, false); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGotoDeclarationTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGotoDeclarationTest.groovy index 48404b0ce742..960adc71fca1 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGotoDeclarationTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGotoDeclarationTest.groovy @@ -1,4 +1,4 @@ -// Copyright 2000-2017 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-2019 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. package org.jetbrains.plugins.groovy import com.intellij.testFramework.LightProjectDescriptor @@ -10,7 +10,7 @@ class GroovyGotoDeclarationTest extends LightGroovyTestCase { final String basePath = TestUtils.testDataPath + "gotoDeclaration/" - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST private void doTest() { def name = getTestName() diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyLightProjectDescriptor.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyLightProjectDescriptor.groovy deleted file mode 100644 index f4a365e03e85..000000000000 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyLightProjectDescriptor.groovy +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2000-2019 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. -package org.jetbrains.plugins.groovy - -import com.intellij.openapi.module.Module -import com.intellij.openapi.roots.ContentEntry -import com.intellij.openapi.roots.ModifiableRootModel -import com.intellij.openapi.roots.OrderRootType -import com.intellij.openapi.roots.libraries.Library -import com.intellij.openapi.vfs.JarFileSystem -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.testFramework.LightProjectDescriptor -import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor -import groovy.transform.CompileStatic -import org.jetbrains.annotations.NotNull - -/** - * @author Max Medvedev - */ -@CompileStatic -class GroovyLightProjectDescriptor extends DefaultLightProjectDescriptor { - public static final LightProjectDescriptor GROOVY_LATEST = GroovyProjectDescriptors.GROOVY_LATEST - public static final LightProjectDescriptor GROOVY_LATEST_REAL_JDK = GroovyProjectDescriptors.GROOVY_LATEST_REAL_JDK - private final String myLibPath - - GroovyLightProjectDescriptor(String libPath) { - myLibPath = libPath - } - - @Override - void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) { - super.configureModule(module, model, contentEntry) - final Library.ModifiableModel modifiableModel = model.moduleLibraryTable.createLibrary("GROOVY").modifiableModel - final VirtualFile groovyJar = JarFileSystem.instance.refreshAndFindFileByPath("${myLibPath}!/") - assert groovyJar != null - modifiableModel.addRoot(groovyJar, OrderRootType.CLASSES) - modifiableModel.commit() - } -} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/SetupRule.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/SetupRule.groovy index 15ec7c73f199..f51f71ec8697 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/SetupRule.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/SetupRule.groovy @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy import com.intellij.testFramework.EdtTestUtil @@ -22,11 +8,13 @@ import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement +import static org.jetbrains.plugins.groovy.GroovyProjectDescriptors.GROOVY_LATEST_REAL_JDK + @CompileStatic class SetupRule implements TestRule { final LightGroovyTestCase testCase = new LightGroovyTestCase() { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST_REAL_JDK + LightProjectDescriptor projectDescriptor = GROOVY_LATEST_REAL_JDK } @Override diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/JsonBuilderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/JsonBuilderTest.groovy index 2b2a9e0a5f61..6195a1391e0a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/JsonBuilderTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/JsonBuilderTest.groovy @@ -1,23 +1,10 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.builder import com.intellij.psi.PsiMethod import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @@ -26,13 +13,11 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression import org.junit.Test -import static org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor.GROOVY_LATEST - // TODO rewrite into Spock test @CompileStatic class JsonBuilderTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test highlighting'() { fixture.configureByText 'a.groovy', '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy index c7dfea525611..dc06bb0c3c16 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/builder/StreamingJsonBuilderTest.groovy @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.builder import com.intellij.psi.PsiMethod @@ -20,7 +6,7 @@ import com.intellij.psi.impl.compiled.ClsMethodImpl import com.intellij.psi.impl.light.LightElement import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @@ -32,7 +18,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMe @CompileStatic class StreamingJsonBuilderTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test highlighting'() { myFixture.configureByText 'a.groovy', ''' diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandlerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandlerTest.groovy index 6a0c3d459f1f..19f800ef6862 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandlerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandlerTest.groovy @@ -1,16 +1,16 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.codeInsight.editorActions import com.intellij.openapi.actionSystem.IdeActions import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase @CompileStatic class GroovyMoveLeftRightHandlerTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST private void doTest(String before, String after = null) { fixture.with { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/hint/GroovyInlayParameterHintsProviderTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/hint/GroovyInlayParameterHintsProviderTest.groovy index 90941c5fda11..7641cd93fd41 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/hint/GroovyInlayParameterHintsProviderTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/hint/GroovyInlayParameterHintsProviderTest.groovy @@ -6,13 +6,13 @@ import com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic import org.jdom.Element -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase @CompileStatic class GroovyInlayParameterHintsProviderTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/control/GroovyIdenticalBranchesInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/control/GroovyIdenticalBranchesInspectionTest.groovy index 8e6793d60365..b6fa2b755f8c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/control/GroovyIdenticalBranchesInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/control/GroovyIdenticalBranchesInspectionTest.groovy @@ -1,31 +1,17 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.codeInspection.control import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic import org.jetbrains.annotations.NotNull -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.highlighting.GrHighlightingTestBase import org.jetbrains.plugins.groovy.util.TestUtils @CompileStatic class GroovyIdenticalBranchesInspectionTest extends GrHighlightingTestBase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST String basePath = TestUtils.testDataPath + "inspections/identicalBranches/" @Override diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessaryDefModifierInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessaryDefModifierInspectionTest.groovy index c34ff0006ad5..7d5cd8068864 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessaryDefModifierInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessaryDefModifierInspectionTest.groovy @@ -1,30 +1,16 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.codeInspection.style import com.intellij.codeInspection.actions.CleanupAllIntention import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase @CompileStatic class GrUnnecessaryDefModifierInspectionTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST final GrUnnecessaryDefModifierInspection inspection = new GrUnnecessaryDefModifierInspection() @Override diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessaryPublicModifierInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessaryPublicModifierInspectionTest.groovy index 2c7f2b7309ab..312a374965e1 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessaryPublicModifierInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessaryPublicModifierInspectionTest.groovy @@ -1,32 +1,15 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.codeInspection.style import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase @CompileStatic class GrUnnecessaryPublicModifierInspectionTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test highlighting and fix'() { fixture.with { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspectionTest.groovy index d562d1c03afb..55d544e7c905 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspectionTest.groovy @@ -1,16 +1,16 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.codeInspection.style import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @CompileStatic class GrUnnecessarySemicolonInspectionTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test simple'() { doTest '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/unused/defaultParameter/GrUnusedDefaultParameterInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/unused/defaultParameter/GrUnusedDefaultParameterInspectionTest.groovy index 6d4d198bee1e..0b8f24df4e96 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/unused/defaultParameter/GrUnusedDefaultParameterInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/unused/defaultParameter/GrUnusedDefaultParameterInspectionTest.groovy @@ -1,25 +1,12 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.codeInspection.unused.defaultParameter -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors class GrUnusedDefaultParameterInspectionTest /*extends LightGroovyTestCase*/ { - final GroovyLightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test simple 0'() { testHighlighting '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/builder/GrBuilderTransformationCompletionTestBase.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/builder/GrBuilderTransformationCompletionTestBase.groovy index 46840e270341..002c7b9869b9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/builder/GrBuilderTransformationCompletionTestBase.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/builder/GrBuilderTransformationCompletionTestBase.groovy @@ -1,24 +1,10 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.completion.builder import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic import org.jetbrains.annotations.NotNull -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.completion.CompletionResult import org.jetbrains.plugins.groovy.completion.GroovyCompletionTestBase @@ -30,7 +16,7 @@ abstract class GrBuilderTransformationCompletionTestBase extends GroovyCompletio @Override @NotNull protected LightProjectDescriptor getProjectDescriptor() { - return GroovyLightProjectDescriptor.GROOVY_LATEST + return GroovyProjectDescriptors.GROOVY_LATEST } void doVariantableTest(String text, String... args) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/builder/MiscBuilderTransformationTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/builder/MiscBuilderTransformationTest.groovy index 222977be4979..233b889a5cd5 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/builder/MiscBuilderTransformationTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/builder/MiscBuilderTransformationTest.groovy @@ -1,32 +1,18 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.completion.builder import com.intellij.psi.OriginInfoAwareElement import com.intellij.psi.impl.light.LightElement import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.lang.resolve.ast.builder.BuilderAnnotationContributor @CompileStatic class MiscBuilderTransformationTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test resolve inner class from java'() { myFixture.addFileToProject 'sample/Bean.groovy', '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/newify/NewifyResolveTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/newify/NewifyResolveTest.groovy index 7efe9f412b29..3eb2aff63863 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/newify/NewifyResolveTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/newify/NewifyResolveTest.groovy @@ -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-2019 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. package org.jetbrains.plugins.groovy.ext.newify import com.intellij.psi.PsiMethod import com.intellij.testFramework.LightProjectDescriptor import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.Nullable -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.resolve.GroovyResolveTestCase class NewifyResolveTest extends GroovyResolveTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/newify/NewifySupportTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/newify/NewifySupportTest.groovy index febab34bdb4c..fae4c119c33f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/newify/NewifySupportTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/newify/NewifySupportTest.groovy @@ -1,9 +1,9 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.ext.newify import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection import org.jetbrains.plugins.groovy.lang.highlighting.GrHighlightingTestBase @@ -11,7 +11,7 @@ import org.jetbrains.plugins.groovy.lang.highlighting.GrHighlightingTestBase @CompileStatic class NewifySupportTest extends GrHighlightingTestBase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/spock/SpockLineMarkersTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/spock/SpockLineMarkersTest.groovy index 4c5ef0576b45..a07da273d38b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/spock/SpockLineMarkersTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/ext/spock/SpockLineMarkersTest.groovy @@ -1,31 +1,17 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.ext.spock import com.intellij.codeInsight.TestFrameworks import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.lang.psi.GroovyFile @CompileStatic class SpockLineMarkersTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/CreateConstantFromJavaUsageTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/CreateConstantFromJavaUsageTest.groovy index 49fa17428e22..6b9d765fcb60 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/CreateConstantFromJavaUsageTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/CreateConstantFromJavaUsageTest.groovy @@ -1,14 +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-2019 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. package org.jetbrains.plugins.groovy.fixes import com.intellij.psi.impl.source.PostprocessReformattingAspect import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic import org.jetbrains.annotations.NotNull -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor import org.jetbrains.plugins.groovy.lang.highlighting.GrHighlightingTestBase import org.jetbrains.plugins.groovy.util.TestUtils +import static org.jetbrains.plugins.groovy.GroovyProjectDescriptors.GROOVY_LATEST_REAL_JDK + @CompileStatic class CreateConstantFromJavaUsageTest extends GrHighlightingTestBase { final String getBasePath() { @@ -18,7 +19,7 @@ class CreateConstantFromJavaUsageTest extends GrHighlightingTestBase { @NotNull @Override protected LightProjectDescriptor getProjectDescriptor() { - return GroovyLightProjectDescriptor.GROOVY_LATEST_REAL_JDK + return GROOVY_LATEST_REAL_JDK } private void doTest(String action = 'Create constant', int actionsCount = 1) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrLoosePrecisionFixTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrLoosePrecisionFixTest.groovy index cd0d6e864298..0aa33686f9da 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrLoosePrecisionFixTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrLoosePrecisionFixTest.groovy @@ -1,13 +1,13 @@ -// Copyright 2000-2017 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-2019 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. package org.jetbrains.plugins.groovy.fixes import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.highlighting.GrHighlightingTestBase class GrLoosePrecisionFixTest extends GrHighlightingTestBase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrMultipleAssignmentTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrMultipleAssignmentTest.groovy index c78f7774ef8d..1419400e5ed0 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrMultipleAssignmentTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrMultipleAssignmentTest.groovy @@ -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-2019 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. package org.jetbrains.plugins.groovy.fixes import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.lang.highlighting.GrHighlightingTestBase class GrMultipleAssignmentTest extends GrHighlightingTestBase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST InspectionProfileEntry[] getCustomInspections() { [new GroovyAssignabilityCheckInspection()] } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrSpreadArgumentTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrSpreadArgumentTest.groovy index 469ac2191c42..480f7c59536c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrSpreadArgumentTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/fixes/GrSpreadArgumentTest.groovy @@ -1,27 +1,13 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.fixes import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.highlighting.GrHighlightingTestBase class GrSpreadArgumentTest extends GrHighlightingTestBase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/geb/AbstractGebLightTestCase.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/geb/AbstractGebLightTestCase.groovy deleted file mode 100644 index ab7d58acaab3..000000000000 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/geb/AbstractGebLightTestCase.groovy +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.plugins.groovy.geb - -import com.intellij.openapi.module.Module -import com.intellij.openapi.roots.ContentEntry -import com.intellij.openapi.roots.ModifiableRootModel -import com.intellij.openapi.roots.OrderRootType -import com.intellij.openapi.roots.libraries.Library -import com.intellij.openapi.vfs.JarFileSystem -import com.intellij.testFramework.LightProjectDescriptor -import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase -import org.jetbrains.annotations.NotNull -import org.jetbrains.plugins.groovy.util.TestUtils -/** - * @author Sergey Evdokimov - */ -abstract class AbstractGebLightTestCase extends LightCodeInsightFixtureTestCase { - - static descriptor = new GebProjectDescriptor() - - @NotNull - @Override - protected LightProjectDescriptor getProjectDescriptor() { - return descriptor - } - - -} - -class GebProjectDescriptor extends DefaultLightProjectDescriptor { - void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) { - final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary("GROOVY").getModifiableModel() - - def fs = JarFileSystem.instance - modifiableModel.addRoot(fs.findFileByPath("$TestUtils.mockGroovyLibraryHome/$TestUtils.GROOVY_JAR!/"), OrderRootType.CLASSES) - - def gebJarFolder = new File(TestUtils.absoluteTestDataPath + "/mockGeb") - for (File gebJar : gebJarFolder.listFiles()) { - if (gebJar.name.endsWith('sources.jar')) { - modifiableModel.addRoot(fs.findFileByPath("${gebJar.path}!/"), OrderRootType.SOURCES) - } - else if (gebJar.name.endsWith(".jar")) { - modifiableModel.addRoot(fs.findFileByPath("${gebJar.path}!/"), OrderRootType.CLASSES) - } - } - - modifiableModel.commit() - } -} \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/geb/GebTestsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/geb/GebTestsTest.groovy index 2bf06728a5fa..0ab36a718cc4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/geb/GebTestsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/geb/GebTestsTest.groovy @@ -1,13 +1,33 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.geb +import com.intellij.testFramework.LightProjectDescriptor +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.annotations.NotNull +import org.jetbrains.plugins.groovy.LibraryLightProjectDescriptor +import org.jetbrains.plugins.groovy.RepositoryTestLibrary +import org.jetbrains.plugins.groovy.TestLibrary import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.util.TestUtils -/** - * @author Sergey Evdokimov - */ -class GebTestsTest extends AbstractGebLightTestCase { +import static org.jetbrains.plugins.groovy.GroovyProjectDescriptors.LIB_GROOVY_1_6 + +class GebTestsTest extends LightCodeInsightFixtureTestCase { + + private static final TestLibrary LIB_GEB = new RepositoryTestLibrary( + 'org.codehaus.geb:geb-core:0.7.2', + 'org.codehaus.geb:geb-junit4:0.7.2', + 'org.codehaus.geb:geb-spock:0.7.2', + 'org.codehaus.geb:geb-testng:0.7.2' + ) + + public static final LightProjectDescriptor DESCRIPTOR = new LibraryLightProjectDescriptor(LIB_GROOVY_1_6 + LIB_GEB) + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return DESCRIPTOR + } void testSpockTestMemberCompletion() { myFixture.configureByText("FooTest.groovy", """ @@ -33,7 +53,7 @@ class FooTest extends geb.junit4.GebReportingTest { TestUtils.checkCompletionContains(myFixture, "\$()", "to()", "go()", "currentWindow", "verifyAt()", "title") } - + void testTestNGTestMemberCompletion() { myFixture.configureByText("FooTest.groovy", """ class FooTest extends geb.testng.GebReportingTest { @@ -263,5 +283,4 @@ class A extends geb.Page { } """) } - } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/ide/GroovyRunLineMarkerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/ide/GroovyRunLineMarkerTest.groovy index 1f75c5ba65c2..c2a5a0bb19b9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/ide/GroovyRunLineMarkerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/ide/GroovyRunLineMarkerTest.groovy @@ -1,16 +1,16 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.ide import com.intellij.openapi.util.registry.Registry import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase @CompileStatic class GroovyRunLineMarkerTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToMethodTest.groovy index 5650e38f1e74..f53865d9014c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToMethodTest.groovy @@ -1,39 +1,10 @@ -/* - * 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-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-2019 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. package org.jetbrains.plugins.groovy.inspections import com.intellij.psi.PsiElement import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.changeToMethod.ChangeToMethodInspection import org.jetbrains.plugins.groovy.lang.psi.GroovyFile @@ -44,7 +15,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryE @CompileStatic class GrChangeToMethodTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST final ChangeToMethodInspection inspection = new ChangeToMethodInspection() diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToOperatorTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToOperatorTest.groovy index 04bb66beea65..c05cf7b40697 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToOperatorTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrChangeToOperatorTest.groovy @@ -1,9 +1,9 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.inspections import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.changeToOperator.ChangeToOperatorInspection import org.jetbrains.plugins.groovy.lang.psi.GroovyFile @@ -15,7 +15,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryE @CompileStatic class GrChangeToOperatorTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST final ChangeToOperatorInspection inspection = new ChangeToOperatorInspection() diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrMethodMayBeStaticTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrMethodMayBeStaticTest.groovy index ee6ef3aec994..32b23ea47bf3 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrMethodMayBeStaticTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/inspections/GrMethodMayBeStaticTest.groovy @@ -1,23 +1,9 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.inspections import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.declaration.GrMethodMayBeStaticInspection @@ -27,7 +13,7 @@ import org.jetbrains.plugins.groovy.codeInspection.declaration.GrMethodMayBeStat @CompileStatic class GrMethodMayBeStaticTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST final GrMethodMayBeStaticInspection inspection = new GrMethodMayBeStaticInspection() void testSimple() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrClosureParamsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrClosureParamsTest.groovy index 645c149eef0a..2cb689148144 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrClosureParamsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrClosureParamsTest.groovy @@ -3,14 +3,14 @@ package org.jetbrains.plugins.groovy.lang.highlighting import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @CompileStatic class GrClosureParamsTest extends GrHighlightingTestBase { final String basePath = super.basePath + 'closureParams/' - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test from string with non-fqn options no error'() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrHighlightingAttributesTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrHighlightingAttributesTest.groovy index ba55c711e1c4..440d27ccbea9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrHighlightingAttributesTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrHighlightingAttributesTest.groovy @@ -1,14 +1,14 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.highlighting import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors @CompileStatic class GrHighlightingAttributesTest extends GrHighlightingTestBase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test highlighting attributes'() { fixture.testHighlighting false, true, false, "highlightingAttributes/test.groovy" diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrLatestHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrLatestHighlightingTest.groovy index 07be2c5658a0..5c0451d155fc 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrLatestHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrLatestHighlightingTest.groovy @@ -5,17 +5,19 @@ import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.openapi.util.RecursionManager import com.intellij.testFramework.LightProjectDescriptor import org.jetbrains.annotations.NotNull -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.bugs.GroovyAccessibilityInspection import org.jetbrains.plugins.groovy.codeInspection.noReturnMethod.MissingReturnInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection +import static org.jetbrains.plugins.groovy.GroovyProjectDescriptors.GROOVY_LATEST_REAL_JDK + class GrLatestHighlightingTest extends GrHighlightingTestBase { + @NotNull @Override protected LightProjectDescriptor getProjectDescriptor() { - return GroovyLightProjectDescriptor.GROOVY_LATEST_REAL_JDK + return GROOVY_LATEST_REAL_JDK } @Override diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightUsagesTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightUsagesTest.groovy index 6122b6db91a9..b28d4d3d78db 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightUsagesTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightUsagesTest.groovy @@ -5,7 +5,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfoType import com.intellij.codeInsight.daemon.impl.SeveritiesProvider import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.util.TestUtils @@ -20,7 +20,7 @@ class GroovyHighlightUsagesTest extends LightGroovyTestCase { final List severitiesHighlightInfoTypes = [ELEMENT_UNDER_CARET_READ, ELEMENT_UNDER_CARET_WRITE] } - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST final String basePath = TestUtils.testDataPath + 'highlighting/usages/' diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/psi/ModifiersTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/psi/ModifiersTest.groovy index b7a1d5ae4211..16a9b5ef4ae8 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/psi/ModifiersTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/psi/ModifiersTest.groovy @@ -1,18 +1,16 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.lang.psi import com.intellij.psi.PsiModifier import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase @CompileStatic class ModifiersTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test top level enum is not static'() { fixture.addFileToProject 'classes.groovy', 'enum E {}' diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsTest.groovy index d45829063f5d..3cddcbb3f154 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/FromAbstractTypeMethodsTest.groovy @@ -1,29 +1,15 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection class FromAbstractTypeMethodsTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test stuff'() { fixture.with { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ConstantExpressionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ConstantExpressionTest.groovy index 623ee29747e0..e33c4c67b890 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ConstantExpressionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ConstantExpressionTest.groovy @@ -1,9 +1,9 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import static org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil.getStringArrayValue @@ -12,7 +12,7 @@ import static org.jetbrains.plugins.groovy.util.TestUtils.disableAstLoading @CompileStatic class ConstantExpressionTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST private void addJavaAnnotation() { fixture.addClass '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/CustomMapPropertyTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/CustomMapPropertyTest.groovy index f8b8115b86c7..f698121d1820 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/CustomMapPropertyTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/CustomMapPropertyTest.groovy @@ -7,14 +7,14 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrClassDefin import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod import org.jetbrains.plugins.groovy.lang.resolve.api.GroovyMapProperty import org.jetbrains.plugins.groovy.util.GroovyLatestTest -import org.jetbrains.plugins.groovy.util.ReferenceExpressionTest +import org.jetbrains.plugins.groovy.util.ExpressionTest import org.junit.Before import org.junit.Test import static com.intellij.psi.CommonClassNames.JAVA_LANG_INTEGER @CompileStatic -class CustomMapPropertyTest extends GroovyLatestTest implements ReferenceExpressionTest { +class CustomMapPropertyTest extends GroovyLatestTest implements ExpressionTest { @Before void addClasses() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/DelegatesToSupportTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/DelegatesToSupportTest.groovy index 2755d1400502..6cc39382f5f0 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/DelegatesToSupportTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/DelegatesToSupportTest.groovy @@ -1,23 +1,9 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @@ -25,7 +11,7 @@ import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnr @CompileStatic class DelegatesToSupportTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GrImportContributorTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GrImportContributorTest.groovy index 92924c67746d..22079ba72b8a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GrImportContributorTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GrImportContributorTest.groovy @@ -3,14 +3,14 @@ package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @CompileStatic class GrImportContributorTest extends LightGroovyTestCase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GrNumericLUBTypeTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GrNumericLUBTypeTest.groovy index 677ae95aeb65..ef7040b345b2 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GrNumericLUBTypeTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GrNumericLUBTypeTest.groovy @@ -1,23 +1,9 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression @@ -25,7 +11,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres @CompileStatic class GrNumericLUBTypeTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitCoercionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitCoercionTest.groovy index 12163fcd3a29..08fa0ba9a63b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitCoercionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/GroovyTraitCoercionTest.groovy @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.codeInsight.completion.CompletionType @@ -20,13 +6,13 @@ import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil import com.intellij.testFramework.LightProjectDescriptor import org.jetbrains.plugins.groovy.GroovyFileType -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod class GroovyTraitCoercionTest extends GroovyResolveTestCase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/MapPropertyTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/MapPropertyTest.groovy index 00b1aa65dd23..e44b0467c3e9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/MapPropertyTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/MapPropertyTest.groovy @@ -1,11 +1,11 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import groovy.transform.CompileStatic import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod import org.jetbrains.plugins.groovy.lang.resolve.api.GroovyMapProperty import org.jetbrains.plugins.groovy.util.GroovyLatestTest -import org.jetbrains.plugins.groovy.util.ReferenceExpressionTest +import org.jetbrains.plugins.groovy.util.ExpressionTest import org.junit.Test import static com.intellij.psi.CommonClassNames.JAVA_LANG_INTEGER @@ -13,7 +13,7 @@ import static com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_META_CLASS @CompileStatic -class MapPropertyTest extends GroovyLatestTest implements ReferenceExpressionTest { +class MapPropertyTest extends GroovyLatestTest implements ExpressionTest { @Test void 'arbitrary property in instance context'() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NavigateDelegatedClsMethodsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NavigateDelegatedClsMethodsTest.groovy index dc788403c463..ea3cf25af9ad 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NavigateDelegatedClsMethodsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NavigateDelegatedClsMethodsTest.groovy @@ -1,45 +1,18 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.codeInsight.TargetElementUtil -import com.intellij.openapi.module.Module -import com.intellij.openapi.roots.ContentEntry -import com.intellij.openapi.roots.ModifiableRootModel -import com.intellij.openapi.roots.OrderRootType -import com.intellij.openapi.roots.libraries.Library -import com.intellij.openapi.vfs.JarFileSystem -import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiMethod import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.annotations.NotNull -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor import org.jetbrains.plugins.groovy.LightGroovyTestCase +import org.jetbrains.plugins.groovy.geb.GebTestsTest import org.jetbrains.plugins.groovy.util.TestUtils -import static org.jetbrains.plugins.groovy.util.TestUtils.getAbsoluteTestDataPath - -/** - * @author Max Medvedev - */ class NavigateDelegatedClsMethodsTest extends LightGroovyTestCase { + final String basePath = TestUtils.testDataPath + 'resolve/clsMethod' - final LightProjectDescriptor projectDescriptor = new GroovyLightProjectDescriptor(TestUtils.mockGroovy2_1LibraryName) { - @Override - void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) { - super.configureModule(module, model, contentEntry) - - Library.ModifiableModel gebModel = model.moduleLibraryTable.createLibrary("Geb").modifiableModel - VirtualFile gebJar = JarFileSystem.instance.refreshAndFindFileByPath(absoluteTestDataPath + 'mockGeb/geb-core-0.7.1.jar!/') - assert gebJar != null - gebModel.addRoot(gebJar, OrderRootType.CLASSES) - VirtualFile gebSource = JarFileSystem.instance.refreshAndFindFileByPath(absoluteTestDataPath + 'mockGeb/geb-core-0.7.1-sources.jar!/') - assert gebSource != null - gebModel.addRoot(gebSource, OrderRootType.SOURCES) - - gebModel.commit() - } - } + final LightProjectDescriptor projectDescriptor = GebTestsTest.DESCRIPTOR void testNavigationInGroovy() { myFixture.with { @@ -55,7 +28,7 @@ class A extends Page { def instance = TargetElementUtil.getInstance() def resolved = instance.findTargetElement(editor, instance.allAccepted, editor.caretModel.offset) assertInstanceOf resolved, PsiMethod - assertEquals('NavigableSupport', (resolved as PsiMethod).containingClass.name) + assertEquals('Page', (resolved as PsiMethod).containingClass.name) } } @@ -73,7 +46,7 @@ class A extends Page { def instance = TargetElementUtil.getInstance() def resolved = instance.findTargetElement(editor, instance.allAccepted, editor.caretModel.offset).navigationElement assertInstanceOf resolved, PsiMethod - assertEquals('NavigableSupport', (resolved as PsiMethod).containingClass.name) + assertEquals('Page', (resolved as PsiMethod).containingClass.name) } } } \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NumberMathTypingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NumberMathTypingTest.groovy index 1b4302b1c45c..a0e9dfa74f7f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NumberMathTypingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NumberMathTypingTest.groovy @@ -3,7 +3,7 @@ package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.PsiClassType import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @@ -12,7 +12,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres class NumberMathTypingTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveAttributeTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveAttributeTest.groovy index cbb75723857e..998bf9abc097 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveAttributeTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveAttributeTest.groovy @@ -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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import groovy.transform.CompileStatic import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField import org.jetbrains.plugins.groovy.util.GroovyLatestTest -import org.jetbrains.plugins.groovy.util.ReferenceExpressionTest +import org.jetbrains.plugins.groovy.util.ExpressionTest import org.junit.Before import org.junit.Test @CompileStatic -class ResolveAttributeTest extends GroovyLatestTest implements ReferenceExpressionTest { +class ResolveAttributeTest extends GroovyLatestTest implements ExpressionTest { @Before void addClasses() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy index 3ec35bcda4c2..afd7f9b3bdd1 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassInNewTest.groovy @@ -1,10 +1,10 @@ -// Copyright 2000-2017 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.PsiClass import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.util.TestUtils @@ -13,7 +13,7 @@ import static com.intellij.openapi.util.RecursionManager.assertOnRecursionPreven @CompileStatic class ResolveClassInNewTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST final String basePath = TestUtils.testDataPath + '/resolve/classInNew' diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveFieldVsAccessorTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveFieldVsAccessorTest.groovy index 22bdcc75132e..66f61856eb6f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveFieldVsAccessorTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveFieldVsAccessorTest.groovy @@ -1,9 +1,9 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod @@ -13,7 +13,7 @@ import static org.jetbrains.plugins.groovy.util.ThrowingTransformation.disableTr @CompileStatic class ResolveFieldVsAccessorTest extends GroovyResolveTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test implicit this'() { disableTransformations testRootDisposable diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveIndexPropertyTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveIndexPropertyTest.groovy index f35df31e8e6f..f164d2162b8d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveIndexPropertyTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveIndexPropertyTest.groovy @@ -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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.PsiMethod import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty @@ -15,7 +15,7 @@ import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt.valid @CompileStatic class ResolveIndexPropertyTest extends GroovyResolveTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test prefer single parameter'() { fixture.addFileToProject 'classes.groovy', '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveOperatorAssignmentTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveOperatorAssignmentTest.groovy index 02bad9e4274f..d3eb7968740d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveOperatorAssignmentTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveOperatorAssignmentTest.groovy @@ -1,30 +1,16 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.PsiMethod import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression class ResolveOperatorAssignmentTest extends GroovyResolveTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test resolve both getter & setter'() { fixture.with { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyViaAliasedImportTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyViaAliasedImportTest.groovy index 4d1b4712cf33..e315ec09b447 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyViaAliasedImportTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyViaAliasedImportTest.groovy @@ -1,9 +1,9 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection import org.jetbrains.plugins.groovy.lang.highlighting.GrHighlightingTestBase @@ -12,7 +12,7 @@ import org.jetbrains.plugins.groovy.util.TestUtils @CompileStatic class ResolvePropertyViaAliasedImportTest extends GrHighlightingTestBase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST final String basePath = TestUtils.testDataPath + 'resolve/imports' @Override diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToOnLambdaTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToOnLambdaTest.groovy index 7320604c550c..1c04c4834a0a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToOnLambdaTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToOnLambdaTest.groovy @@ -5,7 +5,7 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiMethod import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression @@ -20,7 +20,7 @@ import static org.jetbrains.plugins.groovy.util.ThrowingTransformation.disableTr @CompileStatic class ResolveWithDelegatesToOnLambdaTest extends GroovyResolveTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test owner first method'() { assertScript '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy index 7c73660eef0b..80f9aeb780ab 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy @@ -1,11 +1,11 @@ -// 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.PsiClass import com.intellij.psi.PsiMethod import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression @@ -20,7 +20,7 @@ import static org.jetbrains.plugins.groovy.util.ThrowingTransformation.disableTr @CompileStatic class ResolveWithDelegatesToTest extends GroovyResolveTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test owner first method'() { assertScript '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/SelfTypeSupportTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/SelfTypeSupportTest.groovy index 8d44c205bf53..2216fcd65723 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/SelfTypeSupportTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/SelfTypeSupportTest.groovy @@ -1,24 +1,10 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.PsiElement import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod @@ -26,7 +12,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMe @CompileStatic class SelfTypeSupportTest extends LightGroovyTestCase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST String defaultImports = '''\ import groovy.transform.SelfType ''' diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/dgm/ResolveDGMMethodLatestTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/dgm/ResolveDGMMethodLatestTest.groovy index f06c17b5d588..d08aac55847a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/dgm/ResolveDGMMethodLatestTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/dgm/ResolveDGMMethodLatestTest.groovy @@ -1,30 +1,16 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve.dgm import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod import org.jetbrains.plugins.groovy.lang.resolve.GroovyResolveTestCase @CompileStatic class ResolveDGMMethodLatestTest extends GroovyResolveTestCase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void testCloseable() { myFixture.addClass('package java.io; class Closeable {}') diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/dgm/ResolveExtensionMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/dgm/ResolveExtensionMethodTest.groovy index 8cc5e923ef7f..789d884d210e 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/dgm/ResolveExtensionMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/dgm/ResolveExtensionMethodTest.groovy @@ -6,7 +6,7 @@ import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic import org.intellij.lang.annotations.Language import org.jetbrains.plugins.groovy.GroovyFileType -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod import org.jetbrains.plugins.groovy.lang.resolve.GroovyResolveTestCase @@ -16,7 +16,7 @@ import static org.jetbrains.plugins.groovy.dgm.DGMUtil.ORG_CODEHAUS_GROOVY_RUNTI @CompileStatic class ResolveExtensionMethodTest extends GroovyResolveTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST private void addExtension(String directory = "services", @Language("Groovy") String text) { def factory = PsiFileFactory.getInstance(project) diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/modifiers/GrVisibilityTestBase.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/modifiers/GrVisibilityTestBase.groovy index 6abfadee5faf..d154a91986b8 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/modifiers/GrVisibilityTestBase.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/modifiers/GrVisibilityTestBase.groovy @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.lang.resolve.modifiers import com.intellij.extapi.psi.PsiFileBase @@ -20,7 +6,7 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiModifierListOwner import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.lang.psi.GroovyFile @@ -31,7 +17,7 @@ abstract class GrVisibilityTestBase extends LightGroovyTestCase { private static final String[] VISIBILITY_MODIFIERS = [PUBLIC, PRIVATE, PROTECTED, PACKAGE_LOCAL] - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST protected PsiClass addClass(String packageName = "pckg", String text) { def file = fixture.addFileToProject("$packageName/_.groovy", """\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/InplaceRenameTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/InplaceRenameTest.groovy index 768f0b9abd17..da4d7ad8bcab 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/InplaceRenameTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/rename/InplaceRenameTest.groovy @@ -1,31 +1,17 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.refactoring.rename import com.intellij.testFramework.LightProjectDescriptor import com.intellij.testFramework.fixtures.CodeInsightTestUtil import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.refactoring.rename.inplace.GrMethodInplaceRenameHandler @CompileStatic class InplaceRenameTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST private void doTest(String before, String newName, String after) { fixture.configureByText '_.groovy', before diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/BaseScriptTransformationSupportTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/BaseScriptTransformationSupportTest.groovy index 51283820fddb..afcb7578955b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/BaseScriptTransformationSupportTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/BaseScriptTransformationSupportTest.groovy @@ -1,25 +1,11 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.transformations import com.intellij.psi.PsiClass import com.intellij.psi.util.InheritanceUtil import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyFileImpl import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass @@ -27,7 +13,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass @CompileStatic class BaseScriptTransformationSupportTest extends LightGroovyTestCase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST private void doTest(String text) { fixture.addFileToProject 'base.groovy', 'abstract class MyBaseScript extends Script {}' diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrAutoCloneTransformationSupportTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrAutoCloneTransformationSupportTest.groovy index 6f055c986a44..43fbb640e0e1 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrAutoCloneTransformationSupportTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrAutoCloneTransformationSupportTest.groovy @@ -2,13 +2,13 @@ package org.jetbrains.plugins.groovy.transformations import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression class GrAutoCloneTransformationSupportTest extends LightGroovyTestCase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test clone() return type'() { doExpressionTypeTest '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrNoTransformationsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrNoTransformationsTest.groovy index 3f950187d570..0f4ccee9e0c9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrNoTransformationsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrNoTransformationsTest.groovy @@ -1,11 +1,9 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.transformations import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter import org.jetbrains.plugins.groovy.lang.resolve.GroovyResolveTestCase @@ -15,7 +13,7 @@ import static org.jetbrains.plugins.groovy.util.ThrowingTransformation.disableTr @CompileStatic class GrNoTransformationsTest extends GroovyResolveTestCase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrTransformationsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrTransformationsTest.groovy index 1e8fbc1eee91..6958bb07992e 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrTransformationsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/GrTransformationsTest.groovy @@ -1,16 +1,16 @@ -// Copyright 2000-2017 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-2019 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. package org.jetbrains.plugins.groovy.transformations import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod import org.jetbrains.plugins.groovy.lang.resolve.GroovyResolveTestCase @CompileStatic class GrTransformationsTest extends GroovyResolveTestCase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test skip compiled classes while checking if to include synthetic members'() { def resolved = resolveByText(''' diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/SynchronizedTransformationTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/SynchronizedTransformationTest.groovy index bf7e2a322950..d9e2e0cfa1e7 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/SynchronizedTransformationTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/SynchronizedTransformationTest.groovy @@ -1,25 +1,11 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.transformations import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField @@ -27,7 +13,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField @CompileStatic class SynchronizedTransformationTest extends LightGroovyTestCase { - LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test $lock is used by annotated instance method'() { testHighlighting '''\ diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/immutable/ImmutableTransformationSupportTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/immutable/ImmutableTransformationSupportTest.groovy index bd03cd8920bd..0e146f3fe856 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/immutable/ImmutableTransformationSupportTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/immutable/ImmutableTransformationSupportTest.groovy @@ -1,10 +1,10 @@ -// Copyright 2000-2017 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-2019 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. package org.jetbrains.plugins.groovy.transformations.immutable import com.intellij.codeInsight.completion.CompletionType import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @@ -14,7 +14,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.typedef.members.GrM @CompileStatic class ImmutableTransformationSupportTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/indexedProperty/IndexedPropertyTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/indexedProperty/IndexedPropertyTest.groovy index f1664ae37f6d..2dacdc724bd4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/indexedProperty/IndexedPropertyTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/indexedProperty/IndexedPropertyTest.groovy @@ -1,23 +1,9 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.transformations.indexedProperty import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection @@ -25,7 +11,7 @@ import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnr @CompileStatic class IndexedPropertyTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test all methods resolved'() { fixture.with { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/listenerList/ListenerListTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/listenerList/ListenerListTest.groovy index 489f17a3ed31..ba0956ff2bd7 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/listenerList/ListenerListTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/listenerList/ListenerListTest.groovy @@ -1,23 +1,9 @@ -/* - * 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-2019 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. package org.jetbrains.plugins.groovy.transformations.listenerList import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyFileImpl @@ -25,7 +11,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyFileImpl @CompileStatic class ListenerListTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST @Override void setUp() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonConstructorInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonConstructorInspectionTest.groovy index 1ac32add9080..9e9b21aa2afe 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonConstructorInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonConstructorInspectionTest.groovy @@ -1,30 +1,16 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.transformations.singleton import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.transformations.GroovyTransformationsBundle @CompileStatic class SingletonConstructorInspectionTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void setUp() { super.setUp() diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonNewInstanceInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonNewInstanceInspectionTest.groovy index 8149ebc01b9e..9e7b0d9319a3 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonNewInstanceInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonNewInstanceInspectionTest.groovy @@ -1,29 +1,15 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.transformations.singleton import com.intellij.testFramework.LightProjectDescriptor -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle import org.jetbrains.plugins.groovy.codeInspection.bugs.NewInstanceOfSingletonInspection class SingletonNewInstanceInspectionTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void setUp() { super.setUp() diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonTransformationSupportTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonTransformationSupportTest.groovy index 3da2960f5624..3aa6b7eae37f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonTransformationSupportTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/transformations/singleton/SingletonTransformationSupportTest.groovy @@ -1,23 +1,9 @@ -/* - * Copyright 2000-2016 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-2019 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. package org.jetbrains.plugins.groovy.transformations.singleton import com.intellij.testFramework.LightProjectDescriptor import groovy.transform.CompileStatic -import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyFileImpl @@ -25,7 +11,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyFileImpl @CompileStatic class SingletonTransformationSupportTest extends LightGroovyTestCase { - final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + final LightProjectDescriptor projectDescriptor = GroovyProjectDescriptors.GROOVY_LATEST void 'test highlighting'() { fixture.with { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/util/ExpressionTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/util/ExpressionTest.java new file mode 100644 index 000000000000..aa7c3f0dd361 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/util/ExpressionTest.java @@ -0,0 +1,54 @@ +// Copyright 2000-2019 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. +package org.jetbrains.plugins.groovy.util; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import org.intellij.lang.annotations.Language; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; + +import static com.intellij.testFramework.UsefulTestCase.*; + +public interface ExpressionTest extends ResolveTest, TypingTest { + + default void referenceExpressionTest(@Language("Groovy") String text, + @Nullable Class resolved, + String expectedType) { + GrReferenceExpression expression = lastExpression(text, GrReferenceExpression.class); + resolveTest(expression, resolved); + typingTest(expression, expectedType); + } + + default T referenceExpressionTest(@Nullable Class clazz, @Nullable String expectedType) { + GrReferenceExpression expression = elementUnderCaret(GrReferenceExpression.class); + T resolved = resolveTest(expression, clazz); + typingTest(expression, expectedType); + return resolved; + } + + @NotNull + default T resolveMethodTest(@NotNull Class clazz) { + GrMethodCall expression = elementUnderCaret(GrMethodCall.class); + GroovyResolveResult[] results = expression.multiResolve(false); + PsiElement resolved = assertOneElement(results).getElement(); + return assertInstanceOf(resolved, clazz); + } + + default T methodCallTest(@Nullable Class clazz, @Nullable String expectedType) { + GrMethodCall expression = elementUnderCaret(GrMethodCall.class); + GroovyResolveResult[] results = expression.multiResolve(false); + final T resolved; + if (clazz == null) { + assertEmpty(results); + resolved = null; + } + else { + resolved = assertInstanceOf(assertOneElement(results).getElement(), clazz); + } + typingTest(expression, expectedType); + return resolved; + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/util/ReferenceExpressionTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/util/ReferenceExpressionTest.java deleted file mode 100644 index e11520b072b2..000000000000 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/util/ReferenceExpressionTest.java +++ /dev/null @@ -1,16 +0,0 @@ -// 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. -package org.jetbrains.plugins.groovy.util; - -import com.intellij.psi.PsiElement; -import org.intellij.lang.annotations.Language; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; - -public interface ReferenceExpressionTest extends ResolveTest, TypingTest { - - default void referenceExpressionTest(@Language("Groovy") String text, @Nullable Class resolved, String expectedType) { - GrReferenceExpression expression = lastExpression(text, GrReferenceExpression.class); - resolveTest(expression, resolved); - typingTest(expression, expectedType); - } -} diff --git a/plugins/groovy/testdata/mockGeb/geb-core-0.7.1-sources.jar b/plugins/groovy/testdata/mockGeb/geb-core-0.7.1-sources.jar deleted file mode 100644 index 1bf12be7e9a8f60782d1ed419e6fe0e78270d2ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 84962 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%0DUh4*#(42pj*WsJuCGpV`({?Ip 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 diff --git a/plugins/groovy/testdata/mockGeb/geb-junit4-0.7.0.jar b/plugins/groovy/testdata/mockGeb/geb-junit4-0.7.0.jar deleted file mode 100644 index cdb9b0bacea1638d2f4a140a1be1ab98b99959ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7700 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 F{{UoY3)TPt diff --git a/plugins/groovy/testdata/mockGeb/geb-spock-0.7.1.jar b/plugins/groovy/testdata/mockGeb/geb-spock-0.7.1.jar deleted file mode 100644 index bb768e84f3f9699a11c134550def92f1c28e2cfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9305 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 diff --git a/plugins/groovy/testdata/mockGeb/geb-testng-0.7.2.jar b/plugins/groovy/testdata/mockGeb/geb-testng-0.7.2.jar deleted file mode 100644 index c61f665bb38cdbf3dfc1cfb1c225eae6d976c758..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8010 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 diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/output/MavenImportOutputParser.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/output/MavenImportOutputParser.java index 0ce6b83185cd..4acf073b8611 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/output/MavenImportOutputParser.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/output/MavenImportOutputParser.java @@ -2,15 +2,17 @@ package org.jetbrains.idea.maven.importing.output; import com.intellij.build.events.BuildEvent; -import com.intellij.build.events.MessageEvent; import com.intellij.build.output.BuildOutputInstantReader; import com.intellij.build.output.BuildOutputParser; +import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; public class MavenImportOutputParser implements BuildOutputParser { @Override - public boolean parse(String line, BuildOutputInstantReader reader, Consumer messageConsumer) { + public boolean parse(@NotNull String line, + @NotNull BuildOutputInstantReader reader, + @NotNull Consumer messageConsumer) { return false; } } diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/externalSystemIntegration/output/MavenBuildToolLogTestUtils.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/externalSystemIntegration/output/MavenBuildToolLogTestUtils.java index 2d2d30aff34a..22ae2d145499 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/externalSystemIntegration/output/MavenBuildToolLogTestUtils.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/externalSystemIntegration/output/MavenBuildToolLogTestUtils.java @@ -227,7 +227,7 @@ public abstract class MavenBuildToolLogTestUtils extends UsefulTestCase { } @Override - public Object getBuildId() { + public Object getParentEventId() { throw new UnsupportedOperationException(); } diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java index 4d9bbff479d3..6a6d4046d13f 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleEditor.java @@ -107,7 +107,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document private final JPanel myValuesPanel; private final JPanel myStructureViewPanel; private volatile boolean myDisposed; - private ResourceBundleEditorFileListener myVfsListener; + private final ResourceBundleEditorFileListener myVfsListener; private Editor mySelectedEditor; private String myPropertyToSelectWhenVisible; private final ResourceBundleEditorHighlighter myHighlighter; @@ -200,7 +200,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document } myDataProviderPanel = new DataProviderPanel(splitPanel); - installPropertiesChangeListeners(); + myVfsListener = installPropertiesChangeListeners(); myProject.getMessageBus().connect(myProject).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerListener() { @Override @@ -505,12 +505,10 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document } } - private void installPropertiesChangeListeners() { + @NotNull + private ResourceBundleEditorFileListener installPropertiesChangeListeners() { final VirtualFileManager virtualFileManager = VirtualFileManager.getInstance(); - if (myVfsListener != null) { - throw new AssertionError("Listeners can't be initialized twice"); - } - myVfsListener = new ResourceBundleEditorFileListener(this); + ResourceBundleEditorFileListener myVfsListener = new ResourceBundleEditorFileListener(this); virtualFileManager.addVirtualFileListener(myVfsListener, this); PsiTreeChangeAdapter psiTreeChangeAdapter = new PsiTreeChangeAdapter() { @@ -544,7 +542,9 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document } }; PsiManager.getInstance(myProject).addPsiTreeChangeListener(psiTreeChangeAdapter, this); + return myVfsListener; } + private void selectionChanged() { myBackSlashPressed.clear(); UIUtil.invokeLaterIfNeeded(() -> { @@ -782,7 +782,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document } } } - VirtualFileManager.getInstance().removeVirtualFileListener(myVfsListener); myDisposed = true; Disposer.dispose(myStructureViewComponent); releaseAllEditors(); diff --git a/python/helpers/pydev/_pydev_bundle/pydev_monkey.py b/python/helpers/pydev/_pydev_bundle/pydev_monkey.py index bdb9fc67c1f6..1ce5db4f9c65 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_monkey.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_monkey.py @@ -9,6 +9,8 @@ except: xrange = range +PYTHON_NAMES = ['python', 'jython', 'pypy'] + #=============================================================================== # Things that are dependent on having the pydevd debugger #=============================================================================== @@ -73,15 +75,35 @@ def is_python_args(args): return len(args) > 0 and is_python(args[0]) +def is_executable(path): + return os.access(os.path.abspath(path), os.EX_OK) + + +def starts_with_python_shebang(path): + try: + with open(path) as f: + for line in f: + line = line.strip() + if line: + for name in PYTHON_NAMES: + if line.startswith('#!/usr/bin/env %s' % name): + return True + return False + except UnicodeDecodeError: + return False + except: + traceback.print_exc() + return False + + def is_python(path): if path.endswith("'") or path.endswith('"'): path = path[1:len(path) - 1] filename = os.path.basename(path).lower() - for name in ['python', 'jython', 'pypy']: + for name in PYTHON_NAMES: if filename.find(name) != -1: return True - - return False + return sys.platform != 'win32' and is_executable(path) and starts_with_python_shebang(path) def remove_quotes_from_args(args): @@ -140,6 +162,14 @@ def patch_args(args): return args if is_python(args[0]): + + for name in PYTHON_NAMES: + if args[0].find(name) != -1: + break + else: + # Executable file with Python shebang. + args.insert(0, sys.executable) + ind_c = get_c_option_index(args) if ind_c != -1: @@ -314,6 +344,29 @@ def patch_arg_str_win(arg_str): log_debug("New args: %s" % arg_str) return arg_str + +def patch_fork_exec_executable_list(args, other_args): + # When calling a Python executable script with `subprocess.call` the latest uses the first argument as an executable for `fork_exec`. + # This leads to `subprocess.call(["foo.py", "bar", "baz"])` after patching the args will be transformed into something like + # foo.py pydevd.py --port 59043 --client 127.0.0.1 --multiproc --file foo.py bar baz. + # To fix the issue we need to look inside the `fork_exec` executable list and, if necessary, replace an executable script with Python. + i = 0 + for arg in args: + i += 1 + if arg == '--file': + break + else: + return other_args + executable_list = other_args[0] + if args[i].encode() in executable_list: + return ((sys.executable.encode(),),) + other_args[1:] + return other_args + + +def patch_path(path): + return sys.executable if is_python(path) else path + + def monkey_patch_module(module, funcname, create_func): if hasattr(module, funcname): original_name = 'original_' + funcname @@ -354,7 +407,7 @@ def create_execl(original_name): args = patch_args(args) if is_python_args(args): send_process_will_be_substituted() - return getattr(os, original_name)(path, *args) + return getattr(os, original_name)(patch_path(path), *args) return new_execl @@ -367,7 +420,7 @@ def create_execv(original_name): import os if is_python_args(args): send_process_will_be_substituted() - return getattr(os, original_name)(path, patch_args(args)) + return getattr(os, original_name)(patch_path(path), patch_args(args)) return new_execv @@ -380,7 +433,7 @@ def create_execve(original_name): import os if is_python_args(args): send_process_will_be_substituted() - return getattr(os, original_name)(path, patch_args(args), env) + return getattr(os, original_name)(patch_path(path), patch_args(args), env) return new_execve @@ -429,7 +482,7 @@ def create_fork_exec(original_name): import _posixsubprocess # @UnresolvedImport args = patch_args(args) send_process_created_message() - return getattr(_posixsubprocess, original_name)(args, *other_args) + return getattr(_posixsubprocess, original_name)(args, *patch_fork_exec_executable_list(args, other_args)) return new_fork_exec diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java index ccf4568daf2f..5746616bd1df 100644 --- a/python/src/com/jetbrains/python/formatter/PyBlock.java +++ b/python/src/com/jetbrains/python/formatter/PyBlock.java @@ -43,7 +43,7 @@ import static com.jetbrains.python.psi.PyUtil.as; /** * @author yole */ -public class PyBlock implements ASTBlock { +public class PyBlock implements ASTBlock, ReadOnlyBlockContainer { private static final TokenSet ourListElementTypes = TokenSet.create(PyElementTypes.LIST_LITERAL_EXPRESSION, PyElementTypes.LIST_COMP_EXPRESSION, PyElementTypes.DICT_LITERAL_EXPRESSION, diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java index 11c241e87d86..62232759b7e4 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java @@ -113,13 +113,15 @@ public class PythonSdkUpdater implements StartupActivity { */ public static boolean update(@NotNull Sdk sdk, @Nullable SdkModificator sdkModificator, @Nullable final Project project, @Nullable final Component ownerComponent) { + + final Application application = ApplicationManager.getApplication(); + assert !application.isWriteAccessAllowed() : "Can't update SDK under write action, not allowed in background"; + final String key = PythonSdkType.getSdkKey(sdk); synchronized (ourLock) { ourScheduledToRefresh.add(key); } - final Application application = ApplicationManager.getApplication(); - String sdkHome = sdk.getHomePath(); if (sdkHome != null && (PythonSdkType.isVirtualEnv(sdkHome) || PythonSdkType.isConda(sdk))) { final Future updateSdkFeature = application.executeOnPooledThread(() -> { @@ -247,7 +249,7 @@ public class PythonSdkUpdater implements StartupActivity { /** * Changes the version string of an SDK if it's out of date. - * + *

* May be invoked from any thread. May freeze the current thread while evaluating the run-time Python version. */ private static void updateLocalSdkVersion(@NotNull Sdk sdk, @Nullable SdkModificator sdkModificator) { @@ -265,7 +267,7 @@ public class PythonSdkUpdater implements StartupActivity { /** * Updates the paths of a local SDK. - * + *

* May be invoked from any thread. May freeze the current thread while evaluating sys.path. */ private static boolean updateLocalSdkPaths(@NotNull Sdk sdk, @Nullable SdkModificator sdkModificator, @Nullable Project project) { @@ -288,9 +290,9 @@ public class PythonSdkUpdater implements StartupActivity { /** * Updates the paths of a remote SDK. - * + *

* Requires the skeletons refresh steps to be run before it in order to get remote paths mappings in the additional SDK data. - * + *

* You may invoke it from any thread. Blocks until the commit is done in the AWT thread. */ private static void updateRemoteSdkPaths(@NotNull Sdk sdk, @Nullable Project project) { @@ -326,7 +328,7 @@ public class PythonSdkUpdater implements StartupActivity { /** * Returns all the paths for a remote SDK. - * + *

* Requires the skeletons refresh steps to be run before it in order to get remote paths mappings in the additional SDK data. */ @NotNull @@ -352,7 +354,7 @@ public class PythonSdkUpdater implements StartupActivity { /** * Returns local paths for a remote SDK that have been mapped to remote paths during the skeleton refresh step. - * + *

* Returns all the existing paths except those manually excluded by the user. */ @NotNull @@ -439,7 +441,7 @@ public class PythonSdkUpdater implements StartupActivity { /** * Evaluates sys.path by running the Python interpreter from a local SDK. - * + *

* Returns all the existing paths except those manually excluded by the user. */ @NotNull @@ -455,7 +457,7 @@ public class PythonSdkUpdater implements StartupActivity { /** * Commits new SDK paths using an SDK modificator if the paths have been changed. - * + *

* You may invoke it from any thread. Blocks until the commit is done in the AWT thread. */ private static void commitSdkPathsIfChanged(@NotNull Sdk sdk, @@ -477,7 +479,7 @@ public class PythonSdkUpdater implements StartupActivity { /** * Applies a processor to an SDK modificator or an SDK and commits it. - * + *

* You may invoke it from any threads. Blocks until the commit is done in the AWT thread. */ private static void changeSdkModificator(@NotNull Sdk sdk, @Nullable SdkModificator sdkModificator, @@ -488,7 +490,7 @@ public class PythonSdkUpdater implements StartupActivity { final Sdk sdkInsideInvoke = PythonSdkType.findSdkByKey(key); final SdkModificator effectiveModificator = sdkModificator != null ? sdkModificator : sdkInsideInvoke != null ? sdkInsideInvoke.getSdkModificator() : sdk.getSdkModificator(); - if (processor .process(effectiveModificator)) { + if (processor.process(effectiveModificator)) { effectiveModificator.commitChanges(); } }); diff --git a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationProducer.java b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationProducer.java index 91e813f26ca5..e0c3e29843dd 100644 --- a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationProducer.java +++ b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationProducer.java @@ -57,7 +57,7 @@ public final class PyToxConfigurationProducer extends LazyRunConfigurationProduc final String envName = PyToxTestLocator.getEnvNameFromElement(file); if (envName != null) { configuration.setRunOnlyEnvs(envName); - configuration.setName(String.format("Tox: run on %s", envName)); + configuration.setName(String.format("tox: run on %s", envName)); return true; } @@ -68,7 +68,7 @@ public final class PyToxConfigurationProducer extends LazyRunConfigurationProduc } configuration.setWorkingDirectory(directory.getVirtualFile().getCanonicalPath()); if (TOX_FILE_NAME.equals(file.getName())) { - configuration.setName("Tox"); + configuration.setName("tox"); return true; } return false; diff --git a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationSettings.form b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationSettings.form index 4f438059d92d..a9a761ce37db 100644 --- a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationSettings.form +++ b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationSettings.form @@ -13,7 +13,7 @@ - + diff --git a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationType.java b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationType.java index d11bceb55a9e..cf91ce4ddf05 100644 --- a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationType.java +++ b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationType.java @@ -34,7 +34,7 @@ public final class PyToxConfigurationType implements ConfigurationType { @Override public String getConfigurationTypeDescription() { - return "Tox runner"; + return "tox runner"; } @Override diff --git a/python/testData/debug/test_executable_script_debug.py b/python/testData/debug/test_executable_script_debug.py new file mode 100644 index 000000000000..c2c98ea71573 --- /dev/null +++ b/python/testData/debug/test_executable_script_debug.py @@ -0,0 +1,7 @@ +from __future__ import print_function +import os +import subprocess + +ret = subprocess.call([os.path.abspath('test_executable_script_debug_helper.py')], stderr=subprocess.PIPE) + +print("Subprocess exited with return code: %d" % ret) diff --git a/python/testData/debug/test_executable_script_debug_helper.py b/python/testData/debug/test_executable_script_debug_helper.py new file mode 100644 index 000000000000..8d8241462543 --- /dev/null +++ b/python/testData/debug/test_executable_script_debug_helper.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +from __future__ import print_function + +x = 42 +print(x) diff --git a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java index 7895516664d0..e2a3a9a08d5b 100644 --- a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java +++ b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java @@ -1951,4 +1951,28 @@ public class PythonDebuggerTest extends PyEnvTestCase { } }); } + + @Test + @StagingOn(os = TestEnv.WINDOWS) + public void testExecutableScriptDebug() { + runPythonTest(new PyDebuggerTask("/debug", "test_executable_script_debug.py") { + @Override + protected void init() { + setMultiprocessDebug(true); + } + + @Override + public void before() { + toggleBreakpoint(getFilePath("test_executable_script_debug_helper.py"), 4); + } + + @Override + public void testing() throws Exception { + waitForPause(); + eval("x").hasValue("42"); + resume(); + waitForOutput("Subprocess exited with return code: 0"); + } + }); + } } diff --git a/python/tools/src/com/jetbrains/python/tools/Utils.kt b/python/tools/src/com/jetbrains/python/tools/Utils.kt index b21cf1dac6c0..a0c09c825258 100644 --- a/python/tools/src/com/jetbrains/python/tools/Utils.kt +++ b/python/tools/src/com/jetbrains/python/tools/Utils.kt @@ -53,7 +53,7 @@ fun createPythonSdkProducer(sdkHome: String): (Project, Module) -> Sdk { run { val sdk = createSdkForPerformance(module, SdkCreationType.SDK_PACKAGES_AND_SKELETONS, sdkHome) UIUtil.invokeAndWaitIfNeeded(Runnable { - ApplicationManager.getApplication().runWriteAction({ PythonSdkUpdater.update(sdk, null, project, null) }) + PythonSdkUpdater.update(sdk, null, project, null) }) sdk } diff --git a/tools/index-tools/src/org/jetbrains/index/stubs/SdkUtils.kt b/tools/index-tools/src/org/jetbrains/index/stubs/SdkUtils.kt index 0195b8244805..55c2a4dfa2e9 100644 --- a/tools/index-tools/src/org/jetbrains/index/stubs/SdkUtils.kt +++ b/tools/index-tools/src/org/jetbrains/index/stubs/SdkUtils.kt @@ -14,6 +14,7 @@ import com.intellij.openapi.vfs.VfsUtil import com.intellij.testFramework.PlatformTestUtil import com.intellij.util.ui.UIUtil import java.io.File +import java.lang.IllegalArgumentException /** * @author traff @@ -60,7 +61,7 @@ fun getOrCreateModule(project: Project, projectPath: String, moduleTypeId: Strin Computable { ModuleManager.getInstance(project).newModule(projectPath, moduleTypeId) } ) - val root = VfsUtil.findFileByIoFile(File(projectPath), true)!! + val root = VfsUtil.findFileByIoFile(File(projectPath), true) ?: throw AssertionError("Can't find $projectPath") ModuleRootModificationUtil.updateModel(module, { t -> val e = t.addContentEntry(root)