diff --git a/compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityLineMarkerProvider.kt b/compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityLineMarkerProvider.kt index e4447d0..f463d50 100644 --- a/compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityLineMarkerProvider.kt +++ b/compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityLineMarkerProvider.kt @@ -76,7 +76,7 @@ public class StabilityLineMarkerProvider : LineMarkerProvider { return null } - val icon = getIcon(analysis.isSkippable, analysis.isRestartable) + val icon = getIcon(analysis) val tooltip = buildTooltip(analysis) return LineMarkerInfo( @@ -92,11 +92,31 @@ public class StabilityLineMarkerProvider : LineMarkerProvider { /** * Gets the appropriate icon based on stability status. + * + * Colors: + * - Green (stable): All parameters are stable, composable is skippable + * - Yellow (runtime): All non-stable parameters are RUNTIME (stability decided at runtime) + * - Red (unstable): Has at least one UNSTABLE parameter */ - private fun getIcon(isSkippable: Boolean, isRestartable: Boolean): Icon { + private fun getIcon(analysis: ComposableStabilityInfo): Icon { + val allParams = analysis.parameters + analysis.receivers.map { + com.skydoves.compose.stability.runtime.ParameterStabilityInfo( + name = it.type, + type = it.type, + stability = it.stability, + reason = null, + ) + } + + val hasUnstable = allParams.any { it.stability == ParameterStability.UNSTABLE } + val hasRuntime = allParams.any { it.stability == ParameterStability.RUNTIME } + val allStable = allParams.all { it.stability == ParameterStability.STABLE } + val color = when { - isSkippable -> Color(settings.stableGutterColorRGB) -// isRestartable -> Color(settings.runtimeGutterColorRGB) + analysis.isSkippable && allStable -> Color(settings.stableGutterColorRGB) + analysis.isSkippable -> Color(settings.stableGutterColorRGB) + hasUnstable -> Color(settings.unstableGutterColorRGB) + hasRuntime -> Color(settings.runtimeGutterColorRGB) else -> Color(settings.unstableGutterColorRGB) } @@ -110,6 +130,14 @@ public class StabilityLineMarkerProvider : LineMarkerProvider { analysis: ComposableStabilityInfo, ): String { return buildString { + val stableCount = analysis.parameters.count { it.stability == ParameterStability.STABLE } + val unstableCount = analysis.parameters.count { it.stability == ParameterStability.UNSTABLE } + val runtimeCount = analysis.parameters.count { it.stability == ParameterStability.RUNTIME } + val totalCount = analysis.parameters.size + + // Check if all non-stable parameters are runtime + val isRuntimeOnly = unstableCount == 0 && runtimeCount > 0 + append( when { analysis.isSkippableInStrongSkippingMode -> @@ -118,6 +146,9 @@ public class StabilityLineMarkerProvider : LineMarkerProvider { analysis.isSkippable -> "āœ… Skippable (all parameters are stable)" + isRuntimeOnly -> + "🟔 Runtime Stability (skippability determined at runtime)" + analysis.isRestartable -> "āš ļø Restartable (not skippable)" @@ -126,13 +157,27 @@ public class StabilityLineMarkerProvider : LineMarkerProvider { }, ) - // Parameter count - val unstableCount = analysis.parameters.count { it.stability != ParameterStability.STABLE } - val totalCount = analysis.parameters.size - + // Parameter count with breakdown if (totalCount > 0) { append("\n") - append("Parameters: ${totalCount - unstableCount}/$totalCount stable") + append("Parameters: $stableCount/$totalCount stable") + if (runtimeCount > 0) { + append(", $runtimeCount runtime") + } + if (unstableCount > 0) { + append(", $unstableCount unstable") + } + } + + // List runtime parameters + if (runtimeCount > 0) { + append("\n") + append("Runtime: ") + append( + analysis.parameters + .filter { it.stability == ParameterStability.RUNTIME } + .joinToString(", ") { it.name }, + ) } // List unstable parameters @@ -141,21 +186,29 @@ public class StabilityLineMarkerProvider : LineMarkerProvider { append("Unstable: ") append( analysis.parameters - .filter { it.stability != ParameterStability.STABLE } + .filter { it.stability == ParameterStability.UNSTABLE } .joinToString(", ") { it.name }, ) } // Receiver information + val stableReceiverCount = analysis.receivers.count { + it.stability == ParameterStability.STABLE + } val unstableReceiverCount = analysis.receivers.count { - it.stability != ParameterStability.STABLE + it.stability == ParameterStability.UNSTABLE + } + val runtimeReceiverCount = analysis.receivers.count { + it.stability == ParameterStability.RUNTIME } val totalReceiverCount = analysis.receivers.size if (totalReceiverCount > 0) { append("\n") - val stableReceivers = totalReceiverCount - unstableReceiverCount - append("Receivers: $stableReceivers/$totalReceiverCount stable") + append("Receivers: $stableReceiverCount/$totalReceiverCount stable") + if (runtimeReceiverCount > 0) { + append(", $runtimeReceiverCount runtime") + } } // List unstable receivers @@ -164,13 +217,22 @@ public class StabilityLineMarkerProvider : LineMarkerProvider { append("Unstable receivers: ") append( analysis.receivers - .filter { it.stability != ParameterStability.STABLE } + .filter { it.stability == ParameterStability.UNSTABLE } .joinToString(", ") { "${it.receiverKind.name.lowercase()}: ${it.type}" }, ) } + // Runtime stability explanation + if (isRuntimeOnly || runtimeCount > 0) { + append("\n\n🟔 Runtime Stability:") + append("\nStability is determined at runtime based on") + append("\nactual parameter values and their implementations.") + append("\nSkippability may change between library versions") + append("\nor when parameter implementations change.") + } + // Additional info for strong skipping mode if (analysis.isSkippableInStrongSkippingMode) { append("\n\nšŸ’” Strong Skipping Mode: All composables are skippable") diff --git a/compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/settings/StabilitySettingsConfigurable.kt b/compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/settings/StabilitySettingsConfigurable.kt index bdf9565..8a961c8 100644 --- a/compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/settings/StabilitySettingsConfigurable.kt +++ b/compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/settings/StabilitySettingsConfigurable.kt @@ -129,7 +129,10 @@ public class StabilitySettingsConfigurable( row("Runtime color:") { runtimeGutterColorPanel = ColorPanel() cell(runtimeGutterColorPanel) - .comment("Color for runtime-determined stability (currently not used)") + .comment( + "Color for composables with only runtime parameters. " + + "Stability is determined at runtime and may vary between library versions.", + ) } }