mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[Java. Terminal] Revert classpath generator and tests for it in for java command completion
IDEA-359243 GitOrigin-RevId: 847ffcfd6509315d3ce95ce16dab4048a52d4005
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2f9de646f0
commit
59cadbb09a
@@ -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") {
|
||||
|
||||
@@ -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<List<ShellCompletionSuggestion>> {
|
||||
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)
|
||||
}
|
||||
+2
-36
@@ -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<String> {
|
||||
val actual: List<ShellCompletionSuggestion> = getCompletions(command)
|
||||
private suspend fun ShellCompletionTestFixture.getCompletionNames(): List<String> {
|
||||
val actual: List<ShellCompletionSuggestion> = getCompletions("java ")
|
||||
return actual.map { it.name }
|
||||
}
|
||||
|
||||
|
||||
+28
-47
@@ -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<List<ShellCompletionSuggestion>> {
|
||||
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<ShellCompletionSuggestion> {
|
||||
val path = getParentPath(typedPrefix, context.shellName)
|
||||
val files: List<String> = 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<String> = 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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user