diff --git a/platform/diff-impl/src/com/intellij/diff/applications/DiffApplication.kt b/platform/diff-impl/src/com/intellij/diff/applications/DiffApplication.kt index 2132ff54408f..f70f7a8a76b9 100644 --- a/platform/diff-impl/src/com/intellij/diff/applications/DiffApplication.kt +++ b/platform/diff-impl/src/com/intellij/diff/applications/DiffApplication.kt @@ -34,6 +34,7 @@ import java.awt.event.WindowAdapter import java.awt.event.WindowEvent private class DiffApplication : ApplicationStarterBase(/* ...possibleArgumentsCount = */ 0, 2, 3) { + override val commandName: String get() = "diff" override val usageMessage: String get() { val scriptName = ApplicationNamesInfo.getInstance().scriptName diff --git a/platform/diff-impl/src/com/intellij/diff/applications/MergeApplication.kt b/platform/diff-impl/src/com/intellij/diff/applications/MergeApplication.kt index 79360c512d61..91983252e25e 100644 --- a/platform/diff-impl/src/com/intellij/diff/applications/MergeApplication.kt +++ b/platform/diff-impl/src/com/intellij/diff/applications/MergeApplication.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.diff.applications import com.intellij.diff.DiffDialogHints @@ -27,6 +27,7 @@ import kotlinx.coroutines.withContext import java.util.concurrent.atomic.AtomicReference internal class MergeApplication : ApplicationStarterBase(3, 4) { + override val commandName: String get() = "merge" override val usageMessage: String get() { val scriptName = ApplicationNamesInfo.getInstance().scriptName @@ -91,4 +92,4 @@ internal class MergeApplication : ApplicationStarterBase(3, 4) { } } } -} \ No newline at end of file +} diff --git a/platform/extensions/src/com/intellij/openapi/extensions/ExtensionPointName.kt b/platform/extensions/src/com/intellij/openapi/extensions/ExtensionPointName.kt index e3aaf75c4e2e..02b9ec88de87 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/ExtensionPointName.kt +++ b/platform/extensions/src/com/intellij/openapi/extensions/ExtensionPointName.kt @@ -1,6 +1,4 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -@file:Suppress("DeprecatedCallableAddReplaceWith", "ReplaceGetOrSet") - package com.intellij.openapi.extensions import com.intellij.openapi.Disposable @@ -69,9 +67,7 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName * * @return first extension matching [predicate], or `null` if there is no such extension. */ - fun findFirstSafe(predicate: Predicate): T? { - return findFirstSafe(predicate = predicate, sequence = getRootPoint().asSequence()) - } + fun findFirstSafe(predicate: Predicate): T? = findFirstSafe(predicate, getRootPoint().asSequence()) /** * Iterates over registered extensions and calls [processor] for each of them. @@ -82,9 +78,7 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName * * @return first not-null value returned by [processor], or `null` if processor didn't return any non-null value. */ - fun computeSafeIfAny(processor: Function): R? { - return computeSafeIfAny(processor = processor::apply, sequence = getRootPoint().asSequence()) - } + fun computeSafeIfAny(processor: Function): R? = computeSafeIfAny(processor::apply, getRootPoint().asSequence()) val extensionsIfPointIsRegistered: List get() = getExtensionsIfPointIsRegistered(null) @@ -98,10 +92,9 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName @Deprecated("Use {@code getExtensionList().stream()}", level = DeprecationLevel.ERROR) fun extensions(): Stream = getRootPoint().asSequence().asStream() - fun hasAnyExtensions(): Boolean { - @Suppress("DEPRECATION") - return (Extensions.getRootArea().getExtensionPointIfRegistered(name) ?: return false).size() != 0 - } + @Suppress("DEPRECATION", "RemoveUnnecessaryParentheses") + fun hasAnyExtensions(): Boolean = + (Extensions.getRootArea().getExtensionPointIfRegistered(name)?.size() ?: 0) != 0 /** * Use [extensionList] for application-level extensions and [ProjectExtensionPointName.getExtensions] for project-level extension instead @@ -123,17 +116,14 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName val point: ExtensionPoint get() = getRootPoint() - fun findExtension(instanceOf: Class): V? { - return getRootPoint().findExtension(aClass = instanceOf, isRequired = false, strictMatch = ThreeState.UNSURE) - } + fun findExtension(instanceOf: Class): V? = + getRootPoint().findExtension(instanceOf, isRequired = false, strictMatch = ThreeState.UNSURE) - fun findExtensionOrFail(exactClass: Class): V { - return getRootPoint().findExtension(aClass = exactClass, isRequired = true, strictMatch = ThreeState.UNSURE)!! - } + fun findExtensionOrFail(instanceOf: Class): V = + getRootPoint().findExtension(instanceOf, isRequired = true, strictMatch = ThreeState.UNSURE)!! - fun findFirstAssignableExtension(instanceOf: Class): V? { - return getRootPoint().findExtension(aClass = instanceOf, isRequired = true, strictMatch = ThreeState.NO) - } + fun findFirstAssignableExtension(instanceOf: Class): V? = + getRootPoint().findExtension(instanceOf, isRequired = true, strictMatch = ThreeState.NO) /** * Do not use it if there is any extension point listener, because in this case behavior is not predictable - @@ -152,9 +142,7 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName fun getIterable(): Iterable = getRootPoint().asSequence().asIterable() @Internal - fun lazySequence(): Sequence { - return getRootPoint().asSequence() - } + fun lazySequence(): Sequence = getRootPoint().asSequence() @Internal fun processWithPluginDescriptor(consumer: (T, PluginDescriptor) -> Unit) { @@ -163,25 +151,21 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName @Deprecated("Pass CoroutineScope to addExtensionPointListener") fun addExtensionPointListener(listener: ExtensionPointListener, parentDisposable: Disposable?) { - getRootPoint().addExtensionPointListener(listener = listener, - invokeForLoadedExtensions = false, - parentDisposable = parentDisposable) + getRootPoint().addExtensionPointListener(listener, invokeForLoadedExtensions = false, parentDisposable) } @Internal fun addExtensionPointListener(coroutineScope: CoroutineScope, listener: ExtensionPointListener) { - getRootPoint().addExtensionPointListener(listener = listener, - invokeForLoadedExtensions = false, - coroutineScope = coroutineScope) + getRootPoint().addExtensionPointListener(coroutineScope, invokeForLoadedExtensions = false, listener) } @Deprecated("Pass CoroutineScope to addExtensionPointListener") fun addExtensionPointListener(listener: ExtensionPointListener) { - getRootPoint().addExtensionPointListener(listener = listener, invokeForLoadedExtensions = false, parentDisposable = null) + getRootPoint().addExtensionPointListener(listener, invokeForLoadedExtensions = false, parentDisposable = null) } fun addExtensionPointListener(areaInstance: AreaInstance, listener: ExtensionPointListener) { - getPointImpl(areaInstance).addExtensionPointListener(listener = listener, invokeForLoadedExtensions = false, parentDisposable = null) + getPointImpl(areaInstance).addExtensionPointListener(listener, invokeForLoadedExtensions = false, parentDisposable = null) } @ApiStatus.ScheduledForRemoval @@ -193,11 +177,11 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName @ApiStatus.ScheduledForRemoval @Deprecated("Pass CoroutineScope to addChangeListener") fun addChangeListener(listener: Runnable, parentDisposable: Disposable?) { - getRootPoint().addChangeListener(listener = listener, parentDisposable = parentDisposable) + getRootPoint().addChangeListener(listener, parentDisposable) } fun addChangeListener(coroutineScope: CoroutineScope, listener: Runnable) { - getRootPoint().addChangeListener(listener = listener, coroutineScope = coroutineScope) + getRootPoint().addChangeListener(coroutineScope, listener) } /** @@ -210,9 +194,8 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName */ @Internal @ApiStatus.Experimental - fun getByGroupingKey(key: K, cacheId: Class<*>, keyMapper: Function): List { - return getByGroupingKey(point = getRootPoint(), cacheId = cacheId, key = key, keyMapper = keyMapper) - } + fun getByGroupingKey(key: K, cacheId: Class<*>, keyMapper: Function): List = + getByGroupingKey(getRootPoint(), cacheId, key, keyMapper) /** * Build cache by arbitrary key using the provided key to value mapper. Return value by key. @@ -221,9 +204,8 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName */ @Internal @ApiStatus.Experimental - fun getByKey(key: K, cacheId: Class<*>, keyMapper: Function): T? { - return getByKey(point = getRootPoint(), key = key, cacheId = cacheId, keyMapper = keyMapper) - } + fun getByKey(key: K, cacheId: Class<*>, keyMapper: Function): T? = + getByKey(getRootPoint(), key, cacheId, keyMapper) /** * Build cache by arbitrary key using the provided key to value mapper. Return value by key. @@ -232,33 +214,24 @@ class ExtensionPointName(name: @NonNls String) : BaseExtensionPointName */ @Internal @ApiStatus.Experimental - fun getByKey( - key: K, - cacheId: Class<*>, - keyMapper: Function, - valueMapper: Function, - ): V? { - return getByKey(point = getRootPoint(), key = key, cacheId = cacheId, keyMapper = keyMapper, valueMapper = valueMapper) - } + fun getByKey(key: K, cacheId: Class<*>, keyMapper: Function, valueMapper: Function): V? = + getByKey(getRootPoint(), key, cacheId, keyMapper, valueMapper) @Internal @ApiStatus.Experimental - fun computeIfAbsent(key: K, cacheId: Class<*>, valueMapper: Function): V { - return computeIfAbsent(point = getRootPoint(), key = key, cacheId = cacheId, valueProducer = valueMapper) - } + fun computeIfAbsent(key: K, cacheId: Class<*>, valueMapper: Function): V = + computeIfAbsent(getRootPoint(), key, cacheId, valueMapper) /** * Cache some value per extension point. */ - fun computeIfAbsent(cacheId: Class<*>, valueMapper: Supplier): V { - return computeIfAbsent(point = getRootPoint(), cacheId = cacheId, valueProducer = valueMapper) - } + fun computeIfAbsent(cacheId: Class<*>, valueMapper: Supplier): V = + computeIfAbsent(getRootPoint(), cacheId, valueMapper) @Internal fun filterableLazySequence(): Sequence> { val point = getRootPoint() - val adapters = point.sortedAdapters - return LazyExtensionSequence(point = point, adapters = adapters) + return LazyExtensionSequence(point, point.sortedAdapters) } @Internal @@ -316,14 +289,10 @@ private class LazyExtensionSequence( private val point: ExtensionPointImpl, private val adapters: List, ) : Sequence> { - override fun iterator(): Iterator> { - return object : Iterator> { - private var currentIndex = 0 - - override fun hasNext(): Boolean = currentIndex < adapters.size - - override fun next(): LazyExtension = LazyExtensionImpl(adapter = adapters.get(currentIndex++), point = point) - } + override fun iterator(): Iterator> = object : Iterator> { + private var currentIndex = 0 + override fun hasNext(): Boolean = currentIndex < adapters.size + override fun next(): LazyExtension = LazyExtensionImpl(adapter = adapters[currentIndex++], point = point) } } @@ -337,12 +306,11 @@ private class LazyExtensionImpl( override val order: LoadingOrder get() = adapter.order - override fun getCustomAttribute(name: String): String? { - return if (adapter is AdapterWithCustomAttributes) adapter.customAttributes.get(name) else null - } + override fun getCustomAttribute(name: String): String? = + if (adapter is AdapterWithCustomAttributes) adapter.customAttributes[name] else null override val instance: T? - get() = createOrError(adapter = adapter, point = point) + get() = createOrError(adapter, point) override val implementationClassName: String get() = adapter.assignableToClassName @@ -376,4 +344,4 @@ private fun createOrError(adapter: ExtensionComponentAdapter, point: E logger>().error(point.componentManager.createError(e, adapter.pluginDescriptor.pluginId)) return null } -} \ No newline at end of file +} diff --git a/platform/ide-core/api-dump.txt b/platform/ide-core/api-dump.txt index 882b71898acf..2ba0ed155f63 100644 --- a/platform/ide-core/api-dump.txt +++ b/platform/ide-core/api-dump.txt @@ -460,7 +460,6 @@ com.intellij.openapi.application.ApplicationStarter - sf:NON_MODAL:I - sf:NOT_IN_EDT:I - canProcessExternalCommandLine():Z -- getCommandName():java.lang.String - getRequiredModality():I - isHeadless():Z - main(java.util.List):V diff --git a/platform/ide-core/src/com/intellij/openapi/application/ApplicationStarter.kt b/platform/ide-core/src/com/intellij/openapi/application/ApplicationStarter.kt index 83366a56952a..a6b0a89ebe68 100644 --- a/platform/ide-core/src/com/intellij/openapi/application/ApplicationStarter.kt +++ b/platform/ide-core/src/com/intellij/openapi/application/ApplicationStarter.kt @@ -1,20 +1,19 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.application import com.intellij.ide.CliResult +import com.intellij.openapi.extensions.ExtensionPointName import org.intellij.lang.annotations.MagicConstant -import org.jetbrains.annotations.ApiStatus.Internal +import org.jetbrains.annotations.ApiStatus -@Internal +@ApiStatus.Internal abstract class ModernApplicationStarter : ApplicationStarter { final override val requiredModality: Int get() = ApplicationStarter.NOT_IN_EDT @Suppress("DeprecatedCallableAddReplaceWith") @Deprecated(message = "use start", level = DeprecationLevel.ERROR) - final override fun main(args: List) { - throw UnsupportedOperationException("Use start(args)") - } + final override fun main(args: List): Unit = throw UnsupportedOperationException("Use start(args)") abstract suspend fun start(args: List) } @@ -31,6 +30,12 @@ interface ApplicationStarter { const val NON_MODAL: Int = 1 const val ANY_MODALITY: Int = 2 const val NOT_IN_EDT: Int = 3 + + private val EP_NAME = ExtensionPointName("com.intellij.appStarter") + + @ApiStatus.Internal + @JvmStatic + fun findStarter(key: String): ApplicationStarter? = EP_NAME.findByIdOrFromInstance(key, idGetter = { "no-${key}" }) } /** @@ -45,14 +50,6 @@ interface ApplicationStarter { val requiredModality: Int get() = NON_MODAL - /** - * Command-line switch to start with this runner. - * For example, return `"inspect"` if you would like to start an app with `"idea.exe inspect ..."` command. - */ - @Deprecated("Specify it as `id` for extension definition in a plugin descriptor") - val commandName: String? - get() = null - /** * Called before application initialization. * @@ -61,7 +58,6 @@ interface ApplicationStarter { fun premain(args: List) {} /** - * * Called when application has been initialized. Invoked in event dispatch thread. * * An application starter should take care of terminating JVM when appropriate by calling [System.exit]. @@ -83,7 +79,6 @@ interface ApplicationStarter { fun canProcessExternalCommandLine(): Boolean = false /** @see [canProcessExternalCommandLine] */ - suspend fun processExternalCommandLine(args: List, currentDirectory: String?): CliResult { + suspend fun processExternalCommandLine(args: List, currentDirectory: String?): CliResult = throw UnsupportedOperationException("Class ${javaClass.name} must implement `processExternalCommandLineAsync()`") - } } diff --git a/platform/lang-impl/src/com/intellij/ide/script/IdeScriptStarter.kt b/platform/lang-impl/src/com/intellij/ide/script/IdeScriptStarter.kt index 3342d4b74b62..a8d5bdbeca88 100644 --- a/platform/lang-impl/src/com/intellij/ide/script/IdeScriptStarter.kt +++ b/platform/lang-impl/src/com/intellij/ide/script/IdeScriptStarter.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.script import com.intellij.ide.CliResult @@ -18,10 +18,8 @@ import java.io.OutputStreamWriter import java.nio.charset.Charset import java.nio.file.Path -/** - * @author gregsh - */ private class IdeScriptStarter : ApplicationStarterBase() { + override val commandName: String get() = "ideScript" override val usageMessage: String get() { val scriptName = ApplicationNamesInfo.getInstance().scriptName diff --git a/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/ApplicationLoader.kt b/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/ApplicationLoader.kt index b4313fe0b451..4eeb329997c9 100644 --- a/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/ApplicationLoader.kt +++ b/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/ApplicationLoader.kt @@ -485,7 +485,7 @@ private suspend fun createAppStarter(args: List, asyncScope: CoroutineSc } else -> { span("app custom starter creation") { - val starter = findStarter(commandName) ?: createDefaultAppStarter() + val starter = ApplicationStarter.findStarter(commandName) ?: createDefaultAppStarter() if (AppMode.isHeadless() && !starter.isHeadless) { val message = BootstrapBundle.message( "bootstrap.error.message.headless", diff --git a/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/IdeStartupWizard.kt b/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/IdeStartupWizard.kt index 954121f2a212..0a02cb551029 100644 --- a/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/IdeStartupWizard.kt +++ b/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/IdeStartupWizard.kt @@ -1,8 +1,7 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.platform.ide.bootstrap import com.intellij.diagnostic.PluginException -import com.intellij.ide.isIdeStartupWizardEnabled import com.intellij.internal.statistic.eventLog.EventLogGroup import com.intellij.internal.statistic.eventLog.events.EventFields import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector @@ -96,7 +95,7 @@ internal suspend fun runStartupWizard(isInitialStart: Job, app: Application) { } } - if (isIdeStartupWizardEnabled) { + if (ConfigImportHelper.isStartupWizardEnabled()) { LOG.info("Passing execution control to $wizard.") wizard.run() firstWizardExecuted = true diff --git a/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.kt b/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.kt index 364c7be6a01f..39e32e1cf67e 100644 --- a/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.kt +++ b/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.kt @@ -12,11 +12,9 @@ import com.intellij.ide.lightEdit.LightEditFeatureUsagesUtil.OpenPlace import com.intellij.ide.lightEdit.LightEditService import com.intellij.ide.lightEdit.LightEditUtil import com.intellij.ide.util.PsiNavigationSupport -import com.intellij.idea.AppMode import com.intellij.notification.Notification import com.intellij.notification.NotificationType import com.intellij.openapi.application.* -import com.intellij.openapi.application.ex.ApplicationManagerEx import com.intellij.openapi.components.ComponentManagerEx import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.extensions.ExtensionPointName @@ -43,7 +41,7 @@ import com.intellij.util.io.URLUtil import io.netty.handler.codec.http.QueryStringDecoder import kotlinx.coroutines.* import kotlinx.coroutines.future.asDeferred -import org.jetbrains.annotations.ApiStatus.Internal +import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.VisibleForTesting import java.awt.Frame import java.awt.Window @@ -52,27 +50,22 @@ import java.nio.file.Path import java.text.ParseException import java.util.concurrent.CancellationException import kotlin.Boolean +import kotlin.Deprecated +import kotlin.DeprecationLevel import kotlin.Int import kotlin.Result import kotlin.String import kotlin.Suppress import kotlin.Throwable import kotlin.check +import kotlin.collections.any +import kotlin.collections.count import kotlin.error import kotlin.let import kotlin.require import kotlin.requireNotNull import kotlin.use -@get:Internal -val isIdeStartupWizardEnabled: Boolean - get() { - return (!ApplicationManagerEx.isInIntegrationTest() || - System.getProperty("show.wizard.in.test", "false").toBoolean()) && - !AppMode.isRemoteDevHost() && - System.getProperty("intellij.startup.wizard", "true").toBoolean() - } - object CommandLineProcessor { private val LOG = logger() private const val OPTION_WAIT = "--wait" @@ -80,11 +73,11 @@ object CommandLineProcessor { @JvmField val OK_FUTURE: Deferred = CompletableDeferred(value = CliResult.OK) - @Internal + @ApiStatus.Internal const val SCHEME_INTERNAL: String = "!!!internal!!!" @VisibleForTesting - @Internal + @ApiStatus.Internal suspend fun doOpenFileOrProject(file: Path, shouldWait: Boolean): CommandLineProcessorResult { if (!LightEditUtil.isForceOpenInLightEditMode()) { val options = OpenProjectTask { @@ -96,13 +89,11 @@ object CommandLineProcessor { try { val project = ProjectUtil.openOrImportAsync(file, options) if (project != null) { - return CommandLineProcessorResult( - project = project, - future = if (shouldWait) CommandLineWaitingManager.getInstance().addHookForProject(project).asDeferred() else OK_FUTURE, - ) + val future = if (shouldWait) CommandLineWaitingManager.getInstance().addHookForProject(project).asDeferred() else OK_FUTURE + return CommandLineProcessorResult(project, future) } } - catch (_: ProcessCanceledException) { + catch (@Suppress("IncorrectCancellationExceptionHandling") _: ProcessCanceledException) { return createError(IdeBundle.message("dialog.message.open.cancelled")) } } @@ -157,6 +148,7 @@ object CommandLineProcessor { else { PsiNavigationSupport.getInstance().createNavigatable(project, file, -1) } + @Suppress("UsagesOfObsoleteApi") (project as ComponentManagerEx).getCoroutineScope().launch(Dispatchers.EDT) { navigatable.navigate(true) } @@ -175,7 +167,7 @@ object CommandLineProcessor { return if (project != null && !LightEdit.owns(project)) project else projects.first() } - @Internal + @ApiStatus.Internal suspend fun processProtocolCommand(rawUri: @NlsSafe String): CliResult { LOG.info("external URI request:\n$rawUri") check(!ApplicationManager.getApplication().isHeadlessEnvironment) { "cannot process URI requests in headless state" } @@ -183,7 +175,7 @@ object CommandLineProcessor { val uri = if (internal) rawUri.substring(SCHEME_INTERNAL.length) else rawUri val separatorStart = uri.indexOf(URLUtil.SCHEME_SEPARATOR) require(separatorStart >= 0) { uri } - val scheme = uri.substring(0, separatorStart) + val scheme = uri.take(separatorStart) val query = uri.substring(separatorStart + URLUtil.SCHEME_SEPARATOR.length) val cliResult = try { @@ -238,9 +230,7 @@ object CommandLineProcessor { val logMessage = StringBuilder() logMessage.append("External command line:").append('\n') logMessage.append("Dir: ").append(currentDirectory).append('\n') - for (arg in args) { - logMessage.append(arg).append('\n') - } + for (arg in args) logMessage.append(arg).append('\n') logMessage.append("-----") LOG.info(logMessage.toString()) if (args.isEmpty()) { @@ -252,13 +242,13 @@ object CommandLineProcessor { } } } - return CommandLineProcessorResult(project = null, future = OK_FUTURE) + return CommandLineProcessorResult(project = null, OK_FUTURE) } - processApplicationStarters(args, currentDirectory)?.let { + processApplicationStarters(args, currentDirectory)?.let { result -> FUSProjectHotStartUpMeasurer.reportStarterUsed() // app focus is up to app starter - return CommandLineProcessorResult(project = null, result = it) + return CommandLineProcessorResult(project = null, result) } val result = processOpenFile(args, currentDirectory) @@ -284,17 +274,14 @@ object CommandLineProcessor { return result } - // find a frame to activate - @Internal - fun findVisibleFrame(): Window? { - // we assume that the most recently created frame is the most relevant one - return Frame.getFrames().asList().asReversed().firstOrNull { it.isVisible } - } + // find a frame to activate (assuming that the most recently created frame is the most relevant one) + @ApiStatus.Internal + fun findVisibleFrame(): Window? = Frame.getFrames().asList().asReversed().firstOrNull { it.isVisible } private suspend fun processApplicationStarters(args: List, currentDirectory: String?): CliResult? { val command = args.first() - val starter = findStarter(command) ?: return null + val starter = ApplicationStarter.findStarter(command) ?: return null if (!starter.canProcessExternalCommandLine()) { return CliResult(1, IdeBundle.message("dialog.message.only.one.instance.can.be.run.at.time", @@ -353,9 +340,11 @@ object CommandLineProcessor { FUSProjectHotStartUpMeasurer.noProjectFound() } else if (commands.size > 1) { - val numberOfProjects = commands.count { command -> command is OpenProjectResult } - val hasLightEditProject = commands.any { command -> (command is OpenProjectResult && command.lightEditMode) || - (command is NoProjectResult && !command.shouldWait && command.lightEditMode) } + val numberOfProjects = commands.count { it is OpenProjectResult } + val hasLightEditProject = commands.any { + it is OpenProjectResult && it.lightEditMode || + it is NoProjectResult && !it.shouldWait && it.lightEditMode + } FUSProjectHotStartUpMeasurer.openingMultipleProjects(false, numberOfProjects, hasLightEditProject) } else { @@ -376,12 +365,7 @@ object CommandLineProcessor { result = when (command) { is OpenProjectResult -> { FUSProjectHotStartUpMeasurer.withProjectContextElement(command.file) { - openFileOrProject(file = command.file, - line = command.line, - column = command.column, - tempProject = command.tempProject, - shouldWait = command.shouldWait, - lightEditMode = command.lightEditMode) + openFileOrProject(command.file, command.line, command.column, command.tempProject, command.shouldWait, command.lightEditMode) } } is NoProjectResult -> { @@ -406,10 +390,7 @@ object CommandLineProcessor { return result ?: error("Parsing result shouldn't be null at this point; args are not empty") } - private fun parseArgs( - args: List, - currentDirectory: String?, - ): Result> { + private fun parseArgs(args: List, currentDirectory: String?): Result> { val openProjectResults = mutableListOf() var line = -1 var column = -1 @@ -458,31 +439,17 @@ object CommandLineProcessor { } val file = parseFilePath(arg, currentDirectory) ?: return Result.failure(ParseException(arg, i)) - openProjectResults += OpenProjectResult( - file = file, - line = line, - column = column, - tempProject = tempProject, - shouldWait = shouldWait, - lightEditMode = lightEditMode - ) - if (shouldWait) { - break - } + openProjectResults += OpenProjectResult(file, line, column, tempProject, shouldWait, lightEditMode) + + if (shouldWait) break + column = -1 line = column tempProject = false i++ } - return Result.success( - openProjectResults.ifEmpty { - listOf(NoProjectResult( - shouldWait = shouldWait, - lightEditMode = lightEditMode - )) - } - ) + return Result.success(openProjectResults.ifEmpty { listOf(NoProjectResult(shouldWait, lightEditMode)) }) } private fun parseFilePath(path: String, currentDirectory: String?): Path? { @@ -500,41 +467,25 @@ object CommandLineProcessor { } } - private suspend fun openFileOrProject(file: Path, - line: Int, - column: Int, - tempProject: Boolean, - shouldWait: Boolean, - lightEditMode: Boolean): CommandLineProcessorResult { - return LightEditUtil.computeWithCommandLineOptions(shouldWait, lightEditMode).use { - val asFile = line != -1 || tempProject - if (asFile) { - doOpenFile(file, line, column, tempProject, shouldWait) - } - else { - doOpenFileOrProject(file, shouldWait) - } - } + private suspend fun openFileOrProject( + file: Path, + line: Int, + column: Int, + tempProject: Boolean, + shouldWait: Boolean, + lightEditMode: Boolean, + ): CommandLineProcessorResult = LightEditUtil.computeWithCommandLineOptions(shouldWait, lightEditMode).use { + val asFile = line != -1 || tempProject + if (asFile) doOpenFile(file, line, column, tempProject, shouldWait) + else doOpenFileOrProject(file, shouldWait) } } -private const val APP_STARTER_EP_NAME = "com.intellij.appStarter" - -/** - * Returns name of the command for this [ApplicationStarter] specified in plugin.xml file. - * It should be used instead of deprecated [ApplicationStarter.commandName]. - */ -@get:Internal +@Deprecated("Replace with a hard-coded name", level = DeprecationLevel.ERROR) +@Suppress("unused") +@get:ApiStatus.Internal val ApplicationStarter.commandNameFromExtension: String? - get() { - return ExtensionPointName(APP_STARTER_EP_NAME) - .filterableLazySequence() - .find { it.implementationClassName == javaClass.name } - ?.id - } - -@Suppress("DEPRECATION") -@Internal -fun findStarter(key: String): ApplicationStarter? { - return ExtensionPointName(APP_STARTER_EP_NAME).findByIdOrFromInstance(key) { it.commandName } -} \ No newline at end of file + get() = ExtensionPointName("com.intellij.appStarter") + .filterableLazySequence() + .find { it.implementationClassName == javaClass.name } + ?.id diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/HeadlessPluginsInstaller.java b/platform/platform-impl/src/com/intellij/ide/plugins/HeadlessPluginsInstaller.java index 78379eaf1268..ee655edc902f 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/HeadlessPluginsInstaller.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/HeadlessPluginsInstaller.java @@ -1,9 +1,8 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.plugins; import com.intellij.externalDependencies.DependencyOnPlugin; import com.intellij.externalDependencies.ExternalDependenciesManager; -import com.intellij.ide.CommandLineProcessorKt; import com.intellij.ide.impl.OpenProjectTaskKt; import com.intellij.ide.impl.ProjectUtil; import com.intellij.openapi.application.ApplicationStarter; @@ -24,6 +23,7 @@ import java.util.*; @SuppressWarnings("UseOfSystemOutOrSystemErr") public class HeadlessPluginsInstaller implements ApplicationStarter { private static final Logger LOG = Logger.getInstance(HeadlessPluginsInstaller.class); + private static final String COMMAND_NAME = "installPlugins"; @Override public int getRequiredModality() { @@ -79,8 +79,7 @@ public class HeadlessPluginsInstaller implements ApplicationStarter { } } - private void printUsageHint() { - var commandName = CommandLineProcessorKt.getCommandNameFromExtension(this); + private static void printUsageHint() { System.out.printf( """ Usage: %s pluginId* repository* (--for-project=)* [--give-consent-to-use-third-party-plugins] @@ -89,7 +88,7 @@ public class HeadlessPluginsInstaller implements ApplicationStarter { If `--for-project` is specified, also installs the required plugins for a project located at . If `--give-consent-to-use-third-party-plugins` is specified, installed third-party plugins will be approved automatically. Without this option, if a third-party plugin is installed, a user will be asked to approve it when the IDE starts.%n""", - commandName); + COMMAND_NAME); } private static void collectProjectRequiredPlugins(Collection collector, List projectPaths) { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/ApplicationStarterBase.kt b/platform/platform-impl/src/com/intellij/openapi/application/ApplicationStarterBase.kt index 877f8ba498c5..6de5dbbf23c3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/ApplicationStarterBase.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/ApplicationStarterBase.kt @@ -3,10 +3,10 @@ package com.intellij.openapi.application import com.intellij.configurationStore.saveSettings import com.intellij.ide.CliResult -import com.intellij.ide.commandNameFromExtension import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.ui.Messages import com.intellij.openapi.util.NlsContexts +import com.intellij.openapi.util.NlsSafe import com.intellij.openapi.vfs.VirtualFile import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers @@ -17,6 +17,7 @@ import kotlin.system.exitProcess @Internal abstract class ApplicationStarterBase protected constructor(private vararg val argsCount: Int) : ModernApplicationStarter() { + abstract val commandName: @NlsSafe String abstract val usageMessage: @NlsContexts.DialogMessage String? override val isHeadless: Boolean @@ -35,7 +36,6 @@ abstract class ApplicationStarterBase protected constructor(private vararg val a override fun canProcessExternalCommandLine(): Boolean = true override suspend fun processExternalCommandLine(args: List, currentDirectory: String?): CliResult { - val commandName = commandNameFromExtension if (!checkArguments(args)) { val title = ApplicationBundle.message("app.command.exec.error.title", commandName) withContext(Dispatchers.EDT) { @@ -59,8 +59,7 @@ abstract class ApplicationStarterBase protected constructor(private vararg val a } } - protected open fun checkArguments(args: List): Boolean = - Arrays.binarySearch(argsCount, args.size - 1) >= 0 && commandNameFromExtension == args[0] + protected open fun checkArguments(args: List): Boolean = Arrays.binarySearch(argsCount, args.size - 1) >= 0 protected abstract suspend fun executeCommand(args: List, currentDirectory: String?): CliResult diff --git a/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java b/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java index c739f8603593..b784858709da 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java @@ -14,6 +14,7 @@ import com.intellij.ide.startup.StartupActionScriptManager; import com.intellij.ide.startup.StartupActionScriptManager.ActionCommand; import com.intellij.ide.ui.laf.LookAndFeelThemeAdapterKt; import com.intellij.idea.AppMode; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.application.impl.ApplicationInfoImpl; import com.intellij.openapi.application.migrations.NotebooksMigration242; import com.intellij.openapi.application.migrations.SpaceMigration252; @@ -76,7 +77,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import static com.intellij.ide.CommandLineProcessorKt.isIdeStartupWizardEnabled; import static com.intellij.ide.SpecialConfigFiles.*; import static com.intellij.ide.plugins.BundledPluginsState.BUNDLED_PLUGINS_FILENAME; import static com.intellij.openapi.application.ImportOldConfigsUsagesCollector.InitialImportScenario.*; @@ -218,7 +218,7 @@ public final class ConfigImportHelper { log.error("Couldn't backup current config or delete current config directory", e); } } - else if (isIdeStartupWizardEnabled()) { + else if (isStartupWizardEnabled()) { if (!guessedOldConfigDirs.isEmpty() && !shouldAskForConfig()) { var bestConfigGuess = guessedOldConfigDirs.getFirstItem(); if (!isConfigOld(bestConfigGuess.second)) { @@ -230,31 +230,28 @@ public final class ConfigImportHelper { } } } - else { - var askForConfig = shouldAskForConfig(); - if (askForConfig) { + else if (shouldAskForConfig()) { + oldConfigDirAndOldIdePath = showDialogAndGetOldConfigPath(guessedOldConfigDirs.getPaths()); + importScenarioStatistics = SHOW_DIALOG_REQUESTED_BY_PROPERTY; + } + else if (guessedOldConfigDirs.isEmpty()) { + if (!veryFirstStartOnThisComputer) { oldConfigDirAndOldIdePath = showDialogAndGetOldConfigPath(guessedOldConfigDirs.getPaths()); - importScenarioStatistics = SHOW_DIALOG_REQUESTED_BY_PROPERTY; + importScenarioStatistics = SHOW_DIALOG_NO_CONFIGS_FOUND; } - else if (guessedOldConfigDirs.isEmpty()) { - if (!veryFirstStartOnThisComputer) { - oldConfigDirAndOldIdePath = showDialogAndGetOldConfigPath(guessedOldConfigDirs.getPaths()); - importScenarioStatistics = SHOW_DIALOG_NO_CONFIGS_FOUND; - } + } + else { + var bestConfigGuess = guessedOldConfigDirs.getFirstItem(); + if (isConfigOld(bestConfigGuess.second)) { + log.info("The best config guess [" + bestConfigGuess.first + "] is too old, it won't be used for importing."); + oldConfigDirAndOldIdePath = showDialogAndGetOldConfigPath(guessedOldConfigDirs.getPaths()); + importScenarioStatistics = SHOW_DIALOG_CONFIGS_ARE_TOO_OLD; } else { - var bestConfigGuess = guessedOldConfigDirs.getFirstItem(); - if (isConfigOld(bestConfigGuess.second)) { - log.info("The best config guess [" + bestConfigGuess.first + "] is too old, it won't be used for importing."); - oldConfigDirAndOldIdePath = showDialogAndGetOldConfigPath(guessedOldConfigDirs.getPaths()); - importScenarioStatistics = SHOW_DIALOG_CONFIGS_ARE_TOO_OLD; - } - else { - oldConfigDirAndOldIdePath = findConfigDirectoryByPath(bestConfigGuess.first); - if (oldConfigDirAndOldIdePath == null) { - logRejectedConfigDirectory(log, "Previous config directory", bestConfigGuess.first); - importScenarioStatistics = CONFIG_DIRECTORY_NOT_FOUND; - } + oldConfigDirAndOldIdePath = findConfigDirectoryByPath(bestConfigGuess.first); + if (oldConfigDirAndOldIdePath == null) { + logRejectedConfigDirectory(log, "Previous config directory", bestConfigGuess.first); + importScenarioStatistics = CONFIG_DIRECTORY_NOT_FOUND; } } } @@ -480,6 +477,13 @@ public final class ConfigImportHelper { } } + public static boolean isStartupWizardEnabled() { + return + (!ApplicationManagerEx.isInIntegrationTest() || Boolean.getBoolean("show.wizard.in.test")) && + !AppMode.isRemoteDevHost() && + Boolean.parseBoolean(System.getProperty("intellij.startup.wizard", "true")); + } + private static boolean shouldAskForConfig() { if (!canAskForConfig()) { return false; diff --git a/platform/platform-impl/src/com/intellij/openapi/application/ExitStarter.kt b/platform/platform-impl/src/com/intellij/openapi/application/ExitStarter.kt index 55acbad1fa95..fb5c71c6d68e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/ExitStarter.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/ExitStarter.kt @@ -1,6 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -@file:Suppress("ConstPropertyName") - +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.application import com.intellij.ide.CliResult @@ -13,6 +11,7 @@ private const val ourRestartParameter = "--restart" @ApiStatus.Internal class ExitStarter private constructor() : ApplicationStarterBase(0, 1, 2) { + override val commandName: String get() = "exit" override val usageMessage: String get() = IdeBundle.message("wrong.number.of.arguments.usage.ide.executable.exit") @@ -33,4 +32,4 @@ class ExitStarter private constructor() : ApplicationStarterBase(0, 1, 2) { application.invokeLater({ application.exit(true, true, restart) }, ModalityState.nonModal()) } } -} \ No newline at end of file +} diff --git a/platform/platform-impl/src/com/intellij/openapi/application/SaveStarter.kt b/platform/platform-impl/src/com/intellij/openapi/application/SaveStarter.kt index 263b037375e2..75e4c56b97e4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/SaveStarter.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/SaveStarter.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.application import com.intellij.configurationStore.saveSettings @@ -9,6 +9,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext private class SaveStarter() : ApplicationStarterBase(0) { + override val commandName: String get() = "save" override val usageMessage: String get() = IdeBundle.message("wrong.number.of.arguments.usage.ide.executable.save") @@ -21,4 +22,4 @@ private class SaveStarter() : ApplicationStarterBase(0) { saveSettings(ApplicationManager.getApplication()) return CliResult.OK } -} \ No newline at end of file +} diff --git a/platform/platform-impl/src/com/intellij/ui/win/RecentProjectApplication.kt b/platform/platform-impl/src/com/intellij/ui/win/RecentProjectApplication.kt index 7f93a86172ce..e031b6580d87 100644 --- a/platform/platform-impl/src/com/intellij/ui/win/RecentProjectApplication.kt +++ b/platform/platform-impl/src/com/intellij/ui/win/RecentProjectApplication.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ui.win import com.intellij.ide.CliResult @@ -9,6 +9,7 @@ import com.intellij.ui.AppIcon import java.nio.file.Path internal class RecentProjectApplication : ApplicationStarterBase(1) { + override val commandName: String get() = "reopen" override val usageMessage: String get() = "This command is used for internal purpose only." //NON-NLS @@ -21,4 +22,4 @@ internal class RecentProjectApplication : ApplicationStarterBase(1) { } return CliResult.OK } -} \ No newline at end of file +} diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/actions/CompletionEvaluationStarter.kt b/plugins/evaluation-plugin/src/com/intellij/cce/actions/CompletionEvaluationStarter.kt index 3c2527de277a..9cb2f37e379f 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/actions/CompletionEvaluationStarter.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/actions/CompletionEvaluationStarter.kt @@ -25,7 +25,6 @@ import com.intellij.cce.util.ExceptionsUtil.stackTraceToString import com.intellij.cce.workspace.Config import com.intellij.cce.workspace.ConfigFactory import com.intellij.cce.workspace.EvaluationWorkspace -import com.intellij.ide.commandNameFromExtension import com.intellij.openapi.application.ApplicationStarter import com.intellij.openapi.application.ex.ApplicationEx.FORCE_EXIT import com.intellij.openapi.application.ex.ApplicationManagerEx @@ -41,8 +40,7 @@ internal class CompletionEvaluationStarter : ApplicationStarter { get() = ApplicationStarter.NOT_IN_EDT override fun main(args: List) { - - fun run() = MainEvaluationCommand() + fun run() = MainEvaluationCommand("ml-evaluate") .subcommands( FullCommand(), GenerateActionsCommand(), @@ -59,7 +57,6 @@ internal class CompletionEvaluationStarter : ApplicationStarter { } .main(args.toList().subList(1, args.size)) - val startTimestamp = System.currentTimeMillis() try { run() @@ -102,7 +99,7 @@ internal class CompletionEvaluationStarter : ApplicationStarter { } } - inner class MainEvaluationCommand : EvaluationCommand(commandNameFromExtension!!, "Evaluate code completion quality in headless mode") { + class MainEvaluationCommand(name: String) : EvaluationCommand(name, "Evaluate code completion quality in headless mode") { override fun run() = Unit } @@ -248,7 +245,7 @@ internal class CompletionEvaluationStarter : ApplicationStarter { try { sessionsStorage.getSessionFiles() } - catch (e: Throwable) { + catch (_: Throwable) { logger.warn("Failed to get session files from workspace ${this.path()}. Probably some evaluation builds failed") emptyList() } @@ -288,4 +285,4 @@ private fun exit(exitCode: Int) { private fun fatalError(msg: String) { System.err.println("Evaluation failed: $msg") exit(1) -} \ No newline at end of file +} diff --git a/plugins/ide-startup/importSettings/src/com/intellij/ide/startup/importSettings/IdeStartupWizardImpl.kt b/plugins/ide-startup/importSettings/src/com/intellij/ide/startup/importSettings/IdeStartupWizardImpl.kt index 3b490bed1950..35c3aece0f50 100644 --- a/plugins/ide-startup/importSettings/src/com/intellij/ide/startup/importSettings/IdeStartupWizardImpl.kt +++ b/plugins/ide-startup/importSettings/src/com/intellij/ide/startup/importSettings/IdeStartupWizardImpl.kt @@ -1,12 +1,12 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ide.startup.importSettings -import com.intellij.ide.isIdeStartupWizardEnabled import com.intellij.ide.startup.importSettings.chooser.ui.OnboardingController import com.intellij.ide.startup.importSettings.data.SettingsService import com.intellij.ide.startup.importSettings.data.StartupWizardService import com.intellij.ide.startup.importSettings.statistics.ImportSettingsEventsCollector import com.intellij.openapi.application.ApplicationNamesInfo +import com.intellij.openapi.application.ConfigImportHelper import com.intellij.openapi.diagnostic.logger import com.intellij.platform.ide.bootstrap.IdeStartupWizard import com.intellij.util.concurrency.ThreadingAssertions @@ -15,7 +15,7 @@ import kotlinx.coroutines.coroutineScope private class IdeStartupWizardImpl : IdeStartupWizard { override suspend fun run() { - if (!isIdeStartupWizardEnabled) return + if (!ConfigImportHelper.isStartupWizardEnabled()) return logger.info("Initial startup wizard is enabled. Will start the wizard.") ThreadingAssertions.assertEventDispatchThread()