diff --git a/plugins/filePrediction/resources/META-INF/plugin.xml b/plugins/filePrediction/resources/META-INF/plugin.xml index 2a657ee7cd74..83ec650e3fd9 100644 --- a/plugins/filePrediction/resources/META-INF/plugin.xml +++ b/plugins/filePrediction/resources/META-INF/plugin.xml @@ -33,6 +33,7 @@ + diff --git a/plugins/filePrediction/src/com/intellij/filePrediction/features/FilePredictionGeneralFeatures.kt b/plugins/filePrediction/src/com/intellij/filePrediction/features/FilePredictionGeneralFeatures.kt index 3e3ad845a312..92cca3b4f9fd 100644 --- a/plugins/filePrediction/src/com/intellij/filePrediction/features/FilePredictionGeneralFeatures.kt +++ b/plugins/filePrediction/src/com/intellij/filePrediction/features/FilePredictionGeneralFeatures.kt @@ -3,39 +3,18 @@ package com.intellij.filePrediction.features import com.intellij.filePrediction.features.FilePredictionFeature.Companion.binary import com.intellij.filePrediction.features.FilePredictionFeature.Companion.fileType -import com.intellij.filePrediction.features.FilePredictionFeature.Companion.numerical import com.intellij.filePrediction.references.ExternalReferencesResult import com.intellij.internal.statistic.collectors.fus.fileTypes.FileTypeUsagesCollector -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project -import com.intellij.openapi.project.guessProjectDir -import com.intellij.openapi.roots.FileIndexFacade -import com.intellij.openapi.util.SystemInfo -import com.intellij.openapi.util.io.FileUtil -import com.intellij.openapi.util.text.StringUtil -import com.intellij.openapi.util.text.StringUtil.toLowerCase import com.intellij.openapi.vfs.VirtualFile -import com.intellij.testFramework.LightVirtualFile -import com.intellij.util.PathUtil import com.intellij.util.ThreeState -import java.io.File -class FilePredictionGeneralFeatures: FilePredictionFeatureProvider { +class FilePredictionGeneralFeatures : FilePredictionFeatureProvider { companion object { private val FEATURES = arrayListOf( - "excluded", "file_type", - "in_library", - "in_project", "in_ref", - "in_source", - "light", - "name_prefix", - "path_prefix", - "prev_file_type", - "relative_path_prefix", - "same_dir", - "same_module" + "prev_file_type" ) } @@ -53,57 +32,10 @@ class FilePredictionGeneralFeatures: FilePredictionFeatureProvider { result["in_ref"] = binary(isInRef == ThreeState.YES) } - addFileTypeFeatures(result, newFile, prevFile) - ApplicationManager.getApplication().runReadAction { - if (newFile.isValid) { - val fileIndex = FileIndexFacade.getInstance(project) - result["in_project"] = binary(fileIndex.isInProjectScope(newFile)) - result["in_source"] = binary(fileIndex.isInSource(newFile)) - result["in_library"] = binary(fileIndex.isInLibraryClasses(newFile) || fileIndex.isInLibrarySource(newFile)) - result["excluded"] = binary(fileIndex.isExcludedFile(newFile)) - - if (prevFile != null && prevFile.isValid) { - val newModule = fileIndex.getModuleForFile(newFile) - result["same_module"] = binary(newModule != null && newModule == fileIndex.getModuleForFile(prevFile)) - } - result["light"] = binary(newFile is LightVirtualFile) - } - } - - if (prevFile != null) { - val newFileName = unify(newFile.name) - val newFilePath = unify(newFile.path) - val prevFileName = unify(prevFile.name) - result["name_prefix"] = numerical(StringUtil.commonPrefixLength(newFileName, prevFileName)) - - val prevFilePath = unify(prevFile.path) - result["path_prefix"] = numerical(StringUtil.commonPrefixLength(newFilePath, prevFilePath)) - - if (!project.isDisposed) { - val baseDir = project.guessProjectDir()?.path?.let { unify(it) } - if (baseDir != null) { - val newRelativePath = FileUtil.getRelativePath(baseDir, newFilePath, File.separatorChar, false) - val prevRelativePath = FileUtil.getRelativePath(baseDir, prevFilePath, File.separatorChar, false) - if (newRelativePath != null && prevRelativePath != null) { - result["relative_path_prefix"] = numerical(StringUtil.commonPrefixLength(newRelativePath, prevRelativePath)) - } - } - } - result["same_dir"] = binary(PathUtil.getParentPath(newFilePath) == PathUtil.getParentPath(prevFilePath)) - } - return result - } - - private fun addFileTypeFeatures(result: MutableMap, newFile: VirtualFile, prevFile: VirtualFile?) { result["file_type"] = fileType(FileTypeUsagesCollector.getSafeFileTypeName(newFile.fileType)) - if (prevFile != null) { result["prev_file_type"] = fileType(FileTypeUsagesCollector.getSafeFileTypeName(prevFile.fileType)) } - } - - private fun unify(path: String) : String { - val caseSensitive = SystemInfo.isFileSystemCaseSensitive - return if (caseSensitive) FileUtil.getNameWithoutExtension(path) else FileUtil.getNameWithoutExtension(toLowerCase(path)) + return result } } diff --git a/plugins/filePrediction/src/com/intellij/filePrediction/features/FilePredictionSimilarityFeatures.kt b/plugins/filePrediction/src/com/intellij/filePrediction/features/FilePredictionSimilarityFeatures.kt new file mode 100644 index 000000000000..80bed305fd2f --- /dev/null +++ b/plugins/filePrediction/src/com/intellij/filePrediction/features/FilePredictionSimilarityFeatures.kt @@ -0,0 +1,89 @@ +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.filePrediction.features + +import com.intellij.filePrediction.features.FilePredictionFeature.Companion.binary +import com.intellij.filePrediction.features.FilePredictionFeature.Companion.numerical +import com.intellij.filePrediction.references.ExternalReferencesResult +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.guessProjectDir +import com.intellij.openapi.roots.FileIndexFacade +import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.util.text.StringUtil.toLowerCase +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.testFramework.LightVirtualFile +import com.intellij.util.PathUtil +import java.io.File + +class FilePredictionSimilarityFeatures : FilePredictionFeatureProvider { + companion object { + private val FEATURES = arrayListOf( + "excluded", + "in_library", + "in_project", + "in_source", + "light", + "name_prefix", + "path_prefix", + "relative_path_prefix", + "same_dir", + "same_module" + ) + } + + override fun getName(): String = "similarity" + + override fun getFeatures(): List = FEATURES + + override fun calculateFileFeatures(project: Project, + newFile: VirtualFile, + prevFile: VirtualFile?, + refs: ExternalReferencesResult): Map { + val result = HashMap() + ApplicationManager.getApplication().runReadAction { + if (newFile.isValid) { + val fileIndex = FileIndexFacade.getInstance(project) + result["in_project"] = binary(fileIndex.isInProjectScope(newFile)) + result["in_source"] = binary(fileIndex.isInSource(newFile)) + result["in_library"] = binary(fileIndex.isInLibraryClasses(newFile) || fileIndex.isInLibrarySource(newFile)) + result["excluded"] = binary(fileIndex.isExcludedFile(newFile)) + + if (prevFile != null && prevFile.isValid) { + val newModule = fileIndex.getModuleForFile(newFile) + result["same_module"] = binary(newModule != null && newModule == fileIndex.getModuleForFile(prevFile)) + } + result["light"] = binary(newFile is LightVirtualFile) + } + } + + if (prevFile != null) { + val newFileName = unify(newFile.name) + val newFilePath = unify(newFile.path) + val prevFileName = unify(prevFile.name) + result["name_prefix"] = numerical(StringUtil.commonPrefixLength(newFileName, prevFileName)) + + val prevFilePath = unify(prevFile.path) + result["path_prefix"] = numerical(StringUtil.commonPrefixLength(newFilePath, prevFilePath)) + + if (!project.isDisposed) { + val baseDir = project.guessProjectDir()?.path?.let { unify(it) } + if (baseDir != null) { + val newRelativePath = FileUtil.getRelativePath(baseDir, newFilePath, File.separatorChar, false) + val prevRelativePath = FileUtil.getRelativePath(baseDir, prevFilePath, File.separatorChar, false) + if (newRelativePath != null && prevRelativePath != null) { + result["relative_path_prefix"] = numerical(StringUtil.commonPrefixLength(newRelativePath, prevRelativePath)) + } + } + } + result["same_dir"] = binary(PathUtil.getParentPath(newFilePath) == PathUtil.getParentPath(prevFilePath)) + } + return result + } + + private fun unify(path: String): String { + val caseSensitive = SystemInfo.isFileSystemCaseSensitive + return if (caseSensitive) FileUtil.getNameWithoutExtension(path) else FileUtil.getNameWithoutExtension(toLowerCase(path)) + } +} diff --git a/plugins/filePrediction/test/com/intellij/filePrediction/features/FilePredictionGeneralFeaturesTest.kt b/plugins/filePrediction/test/com/intellij/filePrediction/features/FilePredictionCommonFeaturesTest.kt similarity index 83% rename from plugins/filePrediction/test/com/intellij/filePrediction/features/FilePredictionGeneralFeaturesTest.kt rename to plugins/filePrediction/test/com/intellij/filePrediction/features/FilePredictionCommonFeaturesTest.kt index cff8820f3ade..3deae0ad393a 100644 --- a/plugins/filePrediction/test/com/intellij/filePrediction/features/FilePredictionGeneralFeaturesTest.kt +++ b/plugins/filePrediction/test/com/intellij/filePrediction/features/FilePredictionCommonFeaturesTest.kt @@ -18,31 +18,52 @@ import org.jetbrains.jps.model.java.JavaSourceRootType import org.jetbrains.jps.model.java.JpsJavaExtensionService import java.io.File -class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase>() { - private fun doTestGeneralFeatures(prevPath: String, newPath: String, featuresProvider: FileFeaturesProducer) { +class FilePredictionCommonFeaturesTest : CodeInsightFixtureTestCase>() { + private fun doTestSimilarityFeatures(prevPath: String, + newPath: String, + expected: FileFeaturesProducer) { + doTestFeatures( + prevPath, newPath, + listOf(FilePredictionSimilarityFeatures()), + expected + ) + } + + private fun doTestFeatures(prevPath: String, newPath: String, + providers: List, + expectedFeaturesProvider: FileFeaturesProducer) { val prevFile = myFixture.addFileToProject(prevPath, "PREVIOUS FILE") val nextFile = myFixture.addFileToProject(newPath, "NEXT FILE") - val provider = FilePredictionGeneralFeatures() - val actual = provider.calculateFileFeatures( - myFixture.project, nextFile.virtualFile, prevFile.virtualFile, FAILED_COMPUTATION - ) - val expected = featuresProvider.produce(myFixture.project) + val actual: MutableMap = hashMapOf() + for (provider in providers) { + val features = provider.calculateFileFeatures( + myFixture.project, nextFile.virtualFile, prevFile.virtualFile, FAILED_COMPUTATION + ) + actual.putAll(features) + } + + val expected = expectedFeaturesProvider.produce(myFixture.project) for (feature in expected.entries) { assertTrue("Cannot find feature '${feature.key}' in $actual", actual.containsKey(feature.key)) assertEquals("The value of feature '${feature.key}' is different from expected", feature.value, actual[feature.key]) } } - private fun doTestGeneralFeatures(newPath: String, configurator: ProjectConfigurator, featuresProvider: FileFeaturesProducer) { + private fun doTestSimilarityFeatures(newPath: String, configurator: ProjectConfigurator, featuresProvider: FileFeaturesProducer) { + doTestFeatures(FilePredictionSimilarityFeatures(), newPath, configurator, featuresProvider) + } + + private fun doTestFeatures(provider: FilePredictionFeatureProvider, + newPath: String, configurator: ProjectConfigurator, + expectedFeaturesProvider: FileFeaturesProducer) { val nextFile = myFixture.addFileToProject(newPath, "NEXT FILE") configurator.configure(myFixture.project, myModule) - val provider = FilePredictionGeneralFeatures() val actual = provider.calculateFileFeatures( myFixture.project, nextFile.virtualFile, null, FAILED_COMPUTATION ) - val expected = featuresProvider.produce(myFixture.project) + val expected = expectedFeaturesProvider.produce(myFixture.project) for (feature in expected.entries) { assertTrue("Cannot find feature '${feature.key}' in $actual", actual.containsKey(feature.key)) assertEquals("The value of feature '${feature.key}' is different from expected", feature.value, actual[feature.key]) @@ -50,7 +71,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase