feat(mpp-idea): add Compose UI module for IntelliJ IDEA 2025.2+#470
feat(mpp-idea): add Compose UI module for IntelliJ IDEA 2025.2+#470
Conversation
- Add mpp-idea module as a composite build (includeBuild) to avoid plugin version conflicts - Use IntelliJ Platform Gradle Plugin 2.10.2 for IDEA 252+ Compose support - Main project continues to use plugin version 2.1.0 for compatibility - Add ToolWindow with Compose UI using Jewel theme - Add ChatApp, ChatViewModel, and CoroutineScopeHolder components - Target IntelliJ IDEA 2025.2.1 (build 252) The composite build approach allows mpp-idea to use a different version of the IntelliJ Platform Gradle Plugin without affecting other modules.
WalkthroughThis PR introduces a new IntelliJ IDEA plugin module ( Changes
Sequence DiagramsequenceDiagram
participant IDE as IntelliJ IDE
participant Factory as ToolWindowFactory
participant Services as CoroutineScopeHolder
participant ViewModel as AutoDevChatViewModel
participant UI as AutoDevChatApp (Compose)
IDE->>Factory: createToolWindowContent(project, toolWindow)
Factory->>Services: project.service(CoroutineScopeHolder)
Services-->>Factory: projectWideCoroutineScope
Factory->>Factory: createScope("AutoDevChat")
Factory->>ViewModel: AutoDevChatViewModel(childScope)
ViewModel-->>Factory: viewModel instance
Factory->>Factory: toolWindow.addComposeTab("Chat")
Factory->>UI: AutoDevChatApp(viewModel)
UI->>ViewModel: collectAsState(chatMessages)
UI->>ViewModel: collectAsState(inputState)
Note over UI,ViewModel: User interactions trigger callbacks
UI->>ViewModel: onInputChanged(text)
UI->>ViewModel: onSendMessage()
ViewModel-->>UI: state updates flow back
UI->>UI: render updated UI
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
augmentcode review |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt (1)
152-208: Consider extracting the send-and-clear logic.The text field clearing logic is duplicated in two places (lines 183 and 200). Consider extracting this into a helper function to improve maintainability.
Apply this refactor:
+ val sendAndClear = { + onSend() + textFieldState.edit { replace(0, length, "") } + } + Row( modifier = Modifier .fillMaxWidth() .padding(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically ) { TextField( state = textFieldState, placeholder = { Text("Type your message...") }, modifier = Modifier .weight(1f) .onPreviewKeyEvent { keyEvent -> if (keyEvent.key == Key.Enter && keyEvent.type == KeyEventType.KeyDown && !isSending) { - onSend() - textFieldState.edit { replace(0, length, "") } + sendAndClear() true } else { false } }, enabled = !isSending ) if (isSending) { DefaultButton(onClick = onAbort) { Text("Stop") } } else { DefaultButton( - onClick = { - onSend() - textFieldState.edit { replace(0, length, "") } - }, + onClick = sendAndClear, enabled = inputState is MessageInputState.Enabled ) { Text("Send") } } }mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt (1)
20-22: Consider using DEBUG level for initialization logging.INFO-level logging in the
initblock will emit a message every time the factory is instantiated, which may be noisy in production logs. Consider usingthisLogger().debug(...)instead, or removing this log if it's only useful during development.init { - thisLogger().info("AutoDevToolWindowFactory initialized - Compose UI for IntelliJ IDEA 252+") + thisLogger().debug("AutoDevToolWindowFactory initialized - Compose UI for IntelliJ IDEA 252+") }mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt (2)
52-53:isLoadingStateFlow is declared but never updated.The
_isLoadingStateFlow is defined but not used anywhere in the current implementation. If it's intended for future AI integration, consider either removing it until needed or adding a TODO comment to clarify its purpose.Either remove the unused state:
- private val _isLoading = MutableStateFlow(false) - val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()Or add a clarifying comment:
+ // TODO: Update isLoading during AI response generation private val _isLoading = MutableStateFlow(false) val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
96-101: Consider simplifying withifEmpty.Minor readability improvement using Kotlin's
ifEmptyextension.fun onAbortMessage() { - _inputState.value = when (val text = _inputState.value.inputText) { - "" -> MessageInputState.Disabled - else -> MessageInputState.Enabled(text) + val text = _inputState.value.inputText + _inputState.value = text.ifEmpty { null }?.let { MessageInputState.Enabled(it) } + ?: MessageInputState.Disabled } - }Alternatively, keep the current
whenexpression as it's clear and explicit.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
mpp-idea/src/main/resources/icons/autodev-toolwindow.svgis excluded by!**/*.svgmpp-idea/src/main/resources/icons/autodev.svgis excluded by!**/*.svg
📒 Files selected for processing (10)
mpp-idea/build.gradle.kts(1 hunks)mpp-idea/settings.gradle.kts(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt(1 hunks)mpp-idea/src/main/resources/META-INF/plugin.xml(1 hunks)mpp-idea/src/main/resources/messages/AutoDevIdeaBundle.properties(1 hunks)settings.gradle.kts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{kt,kts}
📄 CodeRabbit inference engine (AGENTS.md)
Use
expect/actualfor platform-specific code in Kotlin Multiplatform (e.g., file I/O on JVM/JS/Wasm)
Files:
mpp-idea/settings.gradle.ktsmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.ktsettings.gradle.ktsmpp-idea/build.gradle.ktsmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
**/*.{kt,css,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
DO NOT hardcode colors (e.g.,
Color(0xFF...)or#hex). Always use design tokens for consistency across platforms
Files:
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
🧠 Learnings (3)
📚 Learning: 2025-11-29T02:25:03.592Z
Learnt from: CR
Repo: unit-mesh/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T02:25:03.592Z
Learning: Applies to **/{desktopMain,androidMain}/**/*.kt : Compose (Desktop/Android): Use `AutoDevColors` from `cc.unitmesh.devins.ui.compose.theme` or `MaterialTheme.colorScheme`
Applied to files:
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.ktmpp-idea/build.gradle.ktsmpp-idea/src/main/resources/META-INF/plugin.xmlmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
📚 Learning: 2025-11-29T02:25:03.592Z
Learnt from: CR
Repo: unit-mesh/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T02:25:03.592Z
Learning: Build MPP Core: `cd /Volumes/source/ai/autocrud && ./gradlew :mpp-core:assembleJsPackage`
Applied to files:
settings.gradle.kts
📚 Learning: 2025-11-29T02:25:03.592Z
Learnt from: CR
Repo: unit-mesh/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T02:25:03.592Z
Learning: Applies to **/*.{kt,kts} : Use `expect`/`actual` for platform-specific code in Kotlin Multiplatform (e.g., file I/O on JVM/JS/Wasm)
Applied to files:
mpp-idea/build.gradle.kts
🧬 Code graph analysis (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt (1)
AutoDevChatApp(27-84)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build (241)
- GitHub Check: Build (223)
🔇 Additional comments (14)
settings.gradle.kts (1)
20-20: LGTM! Composite build correctly configured.The
includeBuild("mpp-idea")enables the new mpp-idea module as a composite build, which appropriately isolates its IntelliJ Platform Gradle Plugin version from the main project.mpp-idea/settings.gradle.kts (1)
1-16: LGTM! Standard Gradle settings configuration.The settings file correctly configures repositories for plugin management and dependency resolution.
mpp-idea/build.gradle.kts (1)
1-80: LGTM! Build configuration is well-structured.The build file correctly configures:
- Kotlin 2.2.0 with Compose plugin support
- IntelliJ Platform Plugin 2.10.2 for IDEA 252+ support
- JDK 21 toolchain (required for IDEA 2025.2+)
- All necessary bundled Compose modules
- Appropriate compiler options for experimental Compose APIs
mpp-idea/src/main/resources/messages/AutoDevIdeaBundle.properties (1)
1-17: LGTM! Resource bundle is well-organized.The property keys and values are clearly defined for UI localization.
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt (3)
27-84: LGTM! Well-structured Compose UI with proper state management.The main composable correctly:
- Collects state from the ViewModel
- Implements auto-scroll behavior when new messages arrive
- Uses Jewel theme colors (no hardcoded colors - complies with coding guidelines)
- Organizes UI into logical sections (header, messages, input)
86-125: LGTM! Header and empty state are cleanly implemented.Both composables use Jewel theme tokens for consistent styling.
127-150: LGTM! Message bubble styling uses theme tokens correctly.The bubble correctly differentiates user vs. assistant messages using Jewel theme colors, complying with the coding guideline against hardcoded colors.
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt (1)
14-30: LGTM! Coroutine scope service correctly implemented.The service properly:
- Uses constructor injection for the project-wide scope
- Creates child scopes with proper parent-child lifecycle management
- Documents the cancellation requirements clearly
The
@Suppress("UnstableApiUsage")annotation is appropriate for thechildScopeextension.mpp-idea/src/main/resources/META-INF/plugin.xml (1)
1-30: LGTM! Plugin descriptor is correctly configured.The plugin.xml properly:
- Declares the required Compose module dependency
- Registers the CoroutineScopeHolder project service
- Configures the tool window with correct factory, anchor, and icon references
- Links the resource bundle for localization
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt (1)
10-22: Icon resources verified successfully.The icon files referenced in the code exist at the expected paths:
mpp-idea/src/main/resources/icons/autodev-toolwindow.svg✓mpp-idea/src/main/resources/icons/autodev.svg✓The IconLoader.getIcon() calls will resolve correctly to these resources at runtime.
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt (1)
30-40: LGTM!The MVVM wiring is well-structured: the coroutine scope is properly scoped via
CoroutineScopeHolder, theviewModelis registered with the tool window's disposable for lifecycle management, and the Compose tab is correctly added via Jewel'saddComposeTab.mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt (3)
13-25: LGTM!The
MessageInputStatesealed class is well-designed with clear state variants. Usingdata objectforDisabledis idiomatic Kotlin for singleton-like states.
30-35: LGTM!Clean data class definition with sensible defaults.
111-113: LGTM!Proper cleanup by cancelling the coroutine scope on disposal.
Summary
Add a new
mpp-ideamodule that provides Compose UI support for IntelliJ IDEA 2025.2+ (build 252+).Key Changes
Build Configuration
includeBuild) instead ofincludeto isolate mpp-idea's plugin versionNew Components
addComposeTabfor Compose UITechnical Details
Why Composite Build?
Gradle does not allow the same plugin with different versions in a single build. By using
includeBuild("mpp-idea")instead ofinclude("mpp-idea"), mpp-idea becomes an isolated Gradle project that can use its own plugin versions without affecting the main project.Testing
./gradlew buildPlugin- Main project builds successfully./gradlew :mpp-idea:buildPlugin- mpp-idea module builds successfully./gradlew :core:compileKotlin- Core module compiles without git4idea errorsRelated
Closes the CI failure from PR #469 which was caused by globally upgrading the IntelliJ Platform Gradle Plugin version.
Pull Request opened by Augment Code with guidance from the PR author
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.