diff --git a/java/java-terminal/src/com/intellij/java/terminal/JavaShellCommandSpecsProvider.kt b/java/java-terminal/src/com/intellij/java/terminal/JavaShellCommandSpecsProvider.kt index 158296bcba0e..c94cc048766b 100644 --- a/java/java-terminal/src/com/intellij/java/terminal/JavaShellCommandSpecsProvider.kt +++ b/java/java-terminal/src/com/intellij/java/terminal/JavaShellCommandSpecsProvider.kt @@ -54,7 +54,6 @@ class JavaShellCommandSpecsProvider : ShellCommandSpecsProvider { description(JavaTerminalBundle.message("java.command.terminal.classpath.option.description")) argument { displayName(CLASSPATH_ARGUMENT_NAME) - suggestions(JavaShellCommandUtils.classpathSuggestionsGenerator()) } } option("-showversion") { @@ -116,7 +115,6 @@ class JavaShellCommandSpecsProvider : ShellCommandSpecsProvider { description(JavaTerminalBundle.message("java.command.terminal.classpath.option.description")) argument { displayName(CLASSPATH_ARGUMENT_NAME) - suggestions(JavaShellCommandUtils.classpathSuggestionsGenerator()) } } option("--help") { diff --git a/java/java-terminal/src/com/intellij/java/terminal/JavaShellCommandUtils.kt b/java/java-terminal/src/com/intellij/java/terminal/JavaShellCommandUtils.kt index 2debf503d750..b54a47a8fa6a 100644 --- a/java/java-terminal/src/com/intellij/java/terminal/JavaShellCommandUtils.kt +++ b/java/java-terminal/src/com/intellij/java/terminal/JavaShellCommandUtils.kt @@ -2,39 +2,10 @@ package com.intellij.java.terminal import com.intellij.openapi.util.SystemInfo -import com.intellij.terminal.completion.spec.ShellCompletionSuggestion -import com.intellij.terminal.completion.spec.ShellRuntimeContext -import com.intellij.terminal.completion.spec.ShellRuntimeDataGenerator -import org.jetbrains.plugins.terminal.block.completion.spec.ShellDataGenerators -import org.jetbrains.plugins.terminal.block.completion.spec.ShellRuntimeDataGenerator object JavaShellCommandUtils { fun getClassPathSeparator() = when { SystemInfo.isWindows -> ";" else -> ":" } - - fun classpathSuggestionsGenerator(): ShellRuntimeDataGenerator> { - val key = "classpath generator" - return ShellRuntimeDataGenerator( - debugName = key, - getCacheKey = { - val pathInfo = getPathInfo(it) - "$key:${pathInfo.lastSeparatorIndex}:${pathInfo.typedPrefix}" - } - ) { context -> - val pathInfo = getPathInfo(context) - ShellDataGenerators.getFileSuggestions(context, pathInfo.typedPrefix, false, if (pathInfo.lastSeparatorIndex == -1) 0 else pathInfo.lastSeparatorIndex + 1) - } - } - - private fun getPathInfo(context: ShellRuntimeContext): PathInfo { - val separator = getClassPathSeparator() - val currentPrefix = context.typedPrefix - val index = currentPrefix.lastIndexOf(separator) - val newTypedPrefix = if (index == -1) currentPrefix else currentPrefix.substring(index + 1) - return PathInfo(newTypedPrefix, index) - } - - private data class PathInfo(val typedPrefix: String, val lastSeparatorIndex: Int) } \ No newline at end of file diff --git a/java/java-terminal/test/com/intellij/java/terminal/completion/JavaShellCommandSpecsProviderTest.kt b/java/java-terminal/test/com/intellij/java/terminal/completion/JavaShellCommandSpecsProviderTest.kt index 9473d5c36967..e757db0704d0 100644 --- a/java/java-terminal/test/com/intellij/java/terminal/completion/JavaShellCommandSpecsProviderTest.kt +++ b/java/java-terminal/test/com/intellij/java/terminal/completion/JavaShellCommandSpecsProviderTest.kt @@ -3,7 +3,6 @@ package com.intellij.java.terminal.completion import com.intellij.execution.vmOptions.* import com.intellij.java.terminal.JavaShellCommandContext -import com.intellij.java.terminal.JavaShellCommandUtils import com.intellij.openapi.application.ApplicationManager import com.intellij.terminal.completion.spec.ShellCommandResult import com.intellij.terminal.completion.spec.ShellCompletionSuggestion @@ -56,52 +55,19 @@ class JavaShellCommandSpecsProviderTest : BasePlatformTestCase() { UsefulTestCase.assertDoesntContain(fixture.getCompletionNames(), listOf("--add-experimental-exports", "--add-diagnostic-exports", "-XXadvanced")) } - @Test - fun `classpath suggestion generator simple`() = runBlocking { - val fixture = createFixture() - val completion = fixture.getCompletions("java -cp ") - assertSameElements(completion.map { it.name }, listOf("file1.jar", "file2.jar", "dir1/")) - assertTrue(completion.all { it.prefixReplacementIndex == 0}) - } - - @Test - fun `classpath suggestion generator after colon`() = runBlocking { - val separator = JavaShellCommandUtils.getClassPathSeparator() - val fixture = createFixture() - val argument = "file1.jar$separator" - val completion = fixture.getCompletions("java -cp $argument") - assertSameElements(completion.map { it.name }, listOf("file1.jar", "file2.jar", "dir1/")) - assertTrue(completion.all { it.prefixReplacementIndex == argument.length}) - } - - @Test - fun `classpath suggestion generator with double colon`() = runBlocking { - val separator = JavaShellCommandUtils.getClassPathSeparator() - val fixture = createFixture() - val argument = "file1.jar$separator$separator" - val completion = fixture.getCompletions("java -cp $argument") - assertSameElements(completion.map { it.name }, listOf("file1.jar", "file2.jar", "dir1/")) - assertTrue(completion.all { it.prefixReplacementIndex == argument.length}) - } - private fun createFixture(javaVersion: Int = 11): ShellCompletionTestFixture { ApplicationManager.getApplication().replaceService(VMOptionsService::class.java, MockVMOptionsService(), testRootDisposable) val fixture = ShellCompletionTestFixture.builder(project).mockShellCommandResults { command -> if (command == JavaShellCommandContext.JAVA_SHOW_SETTINGS_PROPERTIES_VERSION_COMMAND) { return@mockShellCommandResults ShellCommandResult.create("java.home = /jre/home\njava.version = ${javaVersion}", exitCode = 0) } - - if (command.startsWith("__jetbrains_intellij_get_directory_files")) { - return@mockShellCommandResults ShellCommandResult.create("file1.jar\nfile2.jar\ndir1/", exitCode = 0) - } - return@mockShellCommandResults ShellCommandResult.create("", exitCode = 1) }.build() return fixture } - private suspend fun ShellCompletionTestFixture.getCompletionNames(command: String = "java "): List { - val actual: List = getCompletions(command) + private suspend fun ShellCompletionTestFixture.getCompletionNames(): List { + val actual: List = getCompletions("java ") return actual.map { it.name } } diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/block/completion/spec/ShellDataGenerators.kt b/plugins/terminal/src/org/jetbrains/plugins/terminal/block/completion/spec/ShellDataGenerators.kt index 79f5cc2783cd..479da78d9c79 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/block/completion/spec/ShellDataGenerators.kt +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/block/completion/spec/ShellDataGenerators.kt @@ -5,7 +5,6 @@ import com.intellij.terminal.completion.spec.* import org.jetbrains.annotations.ApiStatus import org.jetbrains.plugins.terminal.TerminalBundle import org.jetbrains.plugins.terminal.block.completion.ShellCommandSpecsManagerImpl -import org.jetbrains.plugins.terminal.block.completion.spec.ShellDataGenerators.getFileSuggestions import org.jetbrains.plugins.terminal.block.completion.spec.impl.ShellCommandSpecImpl import org.jetbrains.plugins.terminal.block.completion.spec.impl.ShellEnvBasedGenerators import java.io.File @@ -25,7 +24,6 @@ object ShellDataGenerators { * Note that the suggestions are not filtered by the file prefix extracted from the [typed prefix][com.intellij.terminal.completion.spec.ShellRuntimeContext.typedPrefix]. * All the files from the base directory extracted from the typed prefix are returned as [ShellCompletionSuggestion]'s. * All prefix matching logic is performed by the core completion logic. - * @see getFileSuggestions */ fun fileSuggestionsGenerator(onlyDirectories: Boolean = false): ShellRuntimeDataGenerator> { val key = if (onlyDirectories) "directories" else "files" @@ -33,54 +31,37 @@ object ShellDataGenerators { debugName = key, getCacheKey = { "$key:${getParentPath(it.typedPrefix, it.shellName)}" } ) { context -> - getFileSuggestions(context, context.typedPrefix, onlyDirectories) - } - } - - /** - * Generates file suggestions for a given typed prefix in the specified shell context. - * - * @param context the runtime context of the shell containing information about the current environment - * @param typedPrefix the typed prefix for which suggestions are generated - * @param onlyDirectories if only directories should be suggested - * @param replacementIndexDelta - */ - suspend fun getFileSuggestions( - context: ShellRuntimeContext, - typedPrefix: String, - onlyDirectories: Boolean, - replacementIndexDelta: Int = 0, - ): List { - val path = getParentPath(typedPrefix, context.shellName) - val files: List = context.getChildFiles(path, onlyDirectories) - val prefixReplacementIndex = path.length + if (context.typedPrefix.startsWith('"')) 1 else 0 + replacementIndexDelta - val suggestions = files.flatMap { - val type = if (it.endsWith(File.separatorChar)) ShellSuggestionType.FOLDER else ShellSuggestionType.FILE - val suggestion = ShellCompletionSuggestion(name = it, type = type, prefixReplacementIndex = prefixReplacementIndex) - if (type == ShellSuggestionType.FILE) { - listOf(suggestion) + val path = getParentPath(context.typedPrefix, context.shellName) + val files: List = context.getChildFiles(path, onlyDirectories) + val prefixReplacementIndex = path.length + if (context.typedPrefix.startsWith('"')) 1 else 0 + val suggestions = files.flatMap { + val type = if (it.endsWith(File.separatorChar)) ShellSuggestionType.FOLDER else ShellSuggestionType.FILE + val suggestion = ShellCompletionSuggestion(name = it, type = type, prefixReplacementIndex = prefixReplacementIndex) + if (type == ShellSuggestionType.FILE) { + listOf(suggestion) + } + else { + // Directory suggestion has a trailing file separator, but suggestion without it is also valid. + // It is needed for the parser to consider it as a valid suggestion and not mark it as something unknown. + val hiddenSuggestion = ShellCompletionSuggestion( + name = it.removeSuffix(File.separator), + type = ShellSuggestionType.FOLDER, + prefixReplacementIndex = prefixReplacementIndex, + isHidden = true + ) + listOf(suggestion, hiddenSuggestion) + } } - else { - // Directory suggestion has a trailing file separator, but suggestion without it is also valid. - // It is needed for the parser to consider it as a valid suggestion and not mark it as something unknown. - val hiddenSuggestion = ShellCompletionSuggestion( - name = it.removeSuffix(File.separator), - type = ShellSuggestionType.FOLDER, - prefixReplacementIndex = prefixReplacementIndex, - isHidden = true - ) - listOf(suggestion, hiddenSuggestion) + val adjustedPrefix = context.typedPrefix.removePrefix("\"").removeSuffix("'") + // If the base path is the same as the typed prefix, then add an empty suggestion. + // Because the current typed prefix is already a valid value of the file argument. + // It is needed for the parser to consider current typed prefix as a valid file suggestion. + if (path.isNotEmpty() && path == adjustedPrefix) { + val emptySuggestion = ShellCompletionSuggestion(name = "", prefixReplacementIndex = prefixReplacementIndex, isHidden = true) + suggestions + emptySuggestion } + else suggestions } - val adjustedPrefix = typedPrefix.removePrefix("\"").removeSuffix("'") - // If the base path is the same as the typed prefix, then add an empty suggestion. - // Because the current typed prefix is already a valid value of the file argument. - // It is needed for the parser to consider current typed prefix as a valid file suggestion. - return if (path.isNotEmpty() && path == adjustedPrefix) { - val emptySuggestion = ShellCompletionSuggestion(name = "", prefixReplacementIndex = prefixReplacementIndex, isHidden = true) - suggestions + emptySuggestion - } - else suggestions } /**