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