Alexey Tsvetkov
4 years ago
committed by
GitHub
7 changed files with 72 additions and 104 deletions
@ -1,99 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (C) 2019 The Android Open Source Project |
|
||||||
* |
|
||||||
* 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.compose.desktop.ide.preview |
|
||||||
|
|
||||||
import com.intellij.execution.actions.ConfigurationContext |
|
||||||
import com.intellij.execution.actions.ConfigurationFromContext |
|
||||||
import com.intellij.execution.actions.LazyRunConfigurationProducer |
|
||||||
import com.intellij.execution.configurations.ConfigurationFactory |
|
||||||
import com.intellij.openapi.components.service |
|
||||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil |
|
||||||
import com.intellij.openapi.util.Ref |
|
||||||
import com.intellij.psi.PsiElement |
|
||||||
import org.jetbrains.compose.common.modulePath |
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction |
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType |
|
||||||
import org.jetbrains.plugins.gradle.service.execution.GradleExternalTaskConfigurationType |
|
||||||
import org.jetbrains.plugins.gradle.service.execution.GradleRunConfiguration |
|
||||||
|
|
||||||
/** |
|
||||||
* Producer of [ComposePreviewRunConfiguration] for `@Composable` functions annotated with [PREVIEW_ANNOTATION_FQN]. The configuration |
|
||||||
* created is initially named after the `@Composable` function, and its fully qualified name is properly set in the configuration. |
|
||||||
* |
|
||||||
* The [ConfigurationContext] where the [ComposePreviewRunConfiguration] is created from can be any descendant of the `@Composable` function |
|
||||||
* in the PSI tree, such as its annotations, function name or even the keyword "fun". |
|
||||||
* |
|
||||||
* Based on com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer from AOSP |
|
||||||
* with modifications |
|
||||||
*/ |
|
||||||
class PreviewRunConfigurationProducer : LazyRunConfigurationProducer<GradleRunConfiguration>() { |
|
||||||
override fun getConfigurationFactory(): ConfigurationFactory = |
|
||||||
GradleExternalTaskConfigurationType.getInstance().factory |
|
||||||
|
|
||||||
override fun isConfigurationFromContext( |
|
||||||
configuration: GradleRunConfiguration, |
|
||||||
context: ConfigurationContext |
|
||||||
): Boolean { |
|
||||||
val composeFunction = context.containingComposePreviewFunction() ?: return false |
|
||||||
return configuration.run { |
|
||||||
name == runConfigurationNameFor(composeFunction) |
|
||||||
&& settings.externalProjectPath == context.modulePath() |
|
||||||
&& settings.taskNames.singleOrNull() == configureDesktopPreviewTaskName |
|
||||||
&& settings.scriptParameters.split(" ").containsAll( |
|
||||||
runConfigurationScriptParameters(composeFunction.composePreviewFunctionFqn(), context.port) |
|
||||||
) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override fun setupConfigurationFromContext( |
|
||||||
configuration: GradleRunConfiguration, |
|
||||||
context: ConfigurationContext, |
|
||||||
sourceElement: Ref<PsiElement> |
|
||||||
): Boolean { |
|
||||||
val composeFunction = context.containingComposePreviewFunction() ?: return false |
|
||||||
// todo: temporary configuration? |
|
||||||
configuration.apply { |
|
||||||
name = runConfigurationNameFor(composeFunction) |
|
||||||
settings.taskNames.add(configureDesktopPreviewTaskName) |
|
||||||
settings.externalProjectPath = ExternalSystemApiUtil.getExternalProjectPath(context.location?.module) |
|
||||||
settings.scriptParameters = |
|
||||||
runConfigurationScriptParameters(composeFunction.composePreviewFunctionFqn(), context.port) |
|
||||||
.joinToString(" ") |
|
||||||
} |
|
||||||
|
|
||||||
return true |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private val configureDesktopPreviewTaskName = "configureDesktopPreview" |
|
||||||
|
|
||||||
private fun runConfigurationNameFor(function: KtNamedFunction): String = |
|
||||||
"Compose Preview: ${function.name!!}" |
|
||||||
|
|
||||||
private fun runConfigurationScriptParameters(target: String, idePort: Int): List<String> = |
|
||||||
listOf( |
|
||||||
"-Pcompose.desktop.preview.target=$target", |
|
||||||
"-Pcompose.desktop.preview.ide.port=${idePort}" |
|
||||||
) |
|
||||||
|
|
||||||
private val ConfigurationContext.port: Int |
|
||||||
get() = project.service<PreviewStateService>().gradleCallbackPort |
|
||||||
|
|
||||||
private fun KtNamedFunction.composePreviewFunctionFqn() = "${getClassName()}.${name}" |
|
||||||
|
|
||||||
private fun ConfigurationContext.containingComposePreviewFunction() = |
|
||||||
psiLocation?.let { location -> location.getNonStrictParentOfType<KtNamedFunction>()?.takeIf { it.isValidComposePreview() } } |
|
@ -0,0 +1,59 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.jetbrains.compose.desktop.ide.preview |
||||||
|
|
||||||
|
import com.intellij.execution.executors.DefaultRunExecutor |
||||||
|
import com.intellij.openapi.actionSystem.AnAction |
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent |
||||||
|
import com.intellij.openapi.components.service |
||||||
|
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings |
||||||
|
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode |
||||||
|
import com.intellij.openapi.externalSystem.task.TaskCallback |
||||||
|
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil.runTask |
||||||
|
import com.intellij.openapi.util.UserDataHolderBase |
||||||
|
import org.jetbrains.plugins.gradle.settings.GradleSettings |
||||||
|
import org.jetbrains.plugins.gradle.util.GradleConstants |
||||||
|
import java.util.concurrent.CompletableFuture |
||||||
|
|
||||||
|
class RunPreviewAction( |
||||||
|
private val fqName: String, |
||||||
|
private val modulePath: String |
||||||
|
) : AnAction({ "Show non-interactive preview" }, PreviewIcons.RUN_PREVIEW) { |
||||||
|
override fun actionPerformed(e: AnActionEvent) { |
||||||
|
val project = e.project!! |
||||||
|
val gradleVmOptions = GradleSettings.getInstance(project).gradleVmOptions |
||||||
|
val settings = ExternalSystemTaskExecutionSettings() |
||||||
|
settings.executionName = "Preview: $fqName" |
||||||
|
settings.externalProjectPath = modulePath |
||||||
|
settings.taskNames = listOf("configureDesktopPreview") |
||||||
|
settings.vmOptions = gradleVmOptions |
||||||
|
settings.externalSystemIdString = GradleConstants.SYSTEM_ID.id |
||||||
|
val gradleCallbackPort = project.service<PreviewStateService>().gradleCallbackPort |
||||||
|
settings.scriptParameters = |
||||||
|
listOf( |
||||||
|
"-Pcompose.desktop.preview.target=$fqName", |
||||||
|
"-Pcompose.desktop.preview.ide.port=$gradleCallbackPort" |
||||||
|
).joinToString(" ") |
||||||
|
val future = CompletableFuture<Nothing>() |
||||||
|
runTask( |
||||||
|
settings, |
||||||
|
DefaultRunExecutor.EXECUTOR_ID, |
||||||
|
project, |
||||||
|
GradleConstants.SYSTEM_ID, |
||||||
|
object : TaskCallback { |
||||||
|
override fun onSuccess() { |
||||||
|
future.complete(null) |
||||||
|
} |
||||||
|
override fun onFailure() { |
||||||
|
future.completeExceptionally(RuntimeException("Preview for $fqName failed")) |
||||||
|
} |
||||||
|
}, |
||||||
|
ProgressExecutionMode.IN_BACKGROUND_ASYNC, |
||||||
|
false, |
||||||
|
UserDataHolderBase() |
||||||
|
) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue