-
Notifications
You must be signed in to change notification settings - Fork 1
feat(mpp-idea): add advanced DevIn input components with SwingPanel integration #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add IdeaInputListener interface for input events - Add IdeaDevInInput with EditorTextField and DevIn language support - Add IdeaBottomToolbar with Jewel-based send/stop/@/settings buttons - Add IdeaInputSection combining input with toolbar - Update IdeaAgentApp to use new IdeaInputSection Features: - Multi-line text input with Enter to send, Shift+Enter for newline - DevIn language syntax highlighting and completion - LookupManager integration for completion popup handling - Workspace path and token count display
- Replace pure Compose IdeaInputSection with SwingPanel-embedded IdeaDevInInput - DevInInputArea now embeds EditorTextField for full DevIn language support - Add text change listener to IdeaDevInInput for Compose state sync - Combine SwingPanel editor with Compose bottom toolbar This enables IntelliJ native completion popup and DevIn syntax highlighting.
|
Caution Review failedThe pull request is closed. WalkthroughAdds a Swing-backed DevIn editor, a Compose input section and bottom toolbar, and integrates them into the IdeaAgentApp chat UI with send/stop/@/settings wiring, token/workspace indicators, and a listener API for editor→host events. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ComposeUI as IdeaInputSection\n(Compose)
participant SwingEditor as IdeaDevInInput\n(Swing Editor)
participant Listener as IdeaInputListener\n(Event)
participant ToolWindow as IdeaAgentApp
participant Toolbar as IdeaBottomToolbar\n(Compose)
User->>ComposeUI: Focus / type
ComposeUI->>SwingEditor: embed via SwingPanel / forward focus
User->>SwingEditor: Type / Press Enter
SwingEditor->>Listener: onTextChanged(text)
SwingEditor->>Listener: onSubmit(text, trigger) when Enter (if not blocked by completion)
Listener->>ToolWindow: deliver submit event
ToolWindow->>ComposeUI: update isProcessing / clear or disable input
User->>Toolbar: Click Send / Stop / @ / Settings
Toolbar->>ToolWindow: emit onSendClick / onStopClick / onAtClick / onSettingsClick
ToolWindow->>SwingEditor: request stop or append text via API/listener
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review completed. 3 suggestions posted.
Comment augment review to trigger a new review at any time.
| // Workspace indicator | ||
| if (!workspacePath.isNullOrEmpty()) { | ||
| val projectName = workspacePath.substringAfterLast('/') | ||
| .ifEmpty { workspacePath.substringAfterLast('\\') } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Windows-style paths, substringAfterLast('/') returns the original path when / is absent, so the .ifEmpty { substringAfterLast('\\') } branch won’t run and projectName becomes the full path; consider detecting the separator or using a path API to extract the last segment to avoid incorrect display.
🤖 Was this useful? React with 👍 or 👎
| val id = UUID.randomUUID() | ||
| val file = LightVirtualFile("IdeaDevInInput-$id", language, "") | ||
|
|
||
| val document = FileDocumentManager.getInstance().getDocument(file) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After recreateDocument(), the internal DocumentListener that forwards to onTextChanged isn’t reattached to the new document, so text-change callbacks stop firing after clear/recreate; consider registering the same listener for the new document (e.g., inside initializeDocumentListeners).
🤖 Was this useful? React with 👍 or 👎
| val file = LightVirtualFile("IdeaDevInInput-$id", language, "") | ||
|
|
||
| val document = FileDocumentManager.getInstance().getDocument(file) | ||
| ?: throw IllegalStateException("Can't create in-memory document") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When replacing the document, listeners attached to the previous document (both external listeners and the anonymous internal one) are not removed, which risks leaks and duplicate callbacks; consider detaching them from the old document before setDocument (Guideline: no_memory_leaks).
🤖 Was this useful? React with 👍 or 👎
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (10)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputListener.kt (1)
4-4: Consider using specific import instead of wildcard.The
java.util.*import is broader than necessary since onlyEventListeneris used from this package.-import java.util.* +import java.util.EventListenermpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt (4)
11-11: Unused import.The
Colorimport fromandroidx.compose.ui.graphicsappears unused in this file as all colors are obtained fromJewelTheme.
46-54: Dual state synchronization could be simplified.Maintaining both
textFieldStateandinputTextwith aLaunchedEffectcollector introduces complexity. Consider using onlytextFieldState.text.toString()directly in the places whereinputTextis referenced, or deriveinputTextas a computed value.
94-98: Duplicate send logic between keyboard handler and button click.The send logic (check
isNotBlank, callonSend, clear text) is duplicated in both theonPreviewKeyEventhandler and theonSendClicklambda. Consider extracting this into a local function to ensure consistency.+ val doSend: () -> Unit = { + if (inputText.isNotBlank()) { + onSend(inputText) + textFieldState.edit { replace(0, length, "") } + } + } + // In onPreviewKeyEvent: - if (inputText.isNotBlank()) { - onSend(inputText) - textFieldState.edit { replace(0, length, "") } - } + doSend() // In IdeaBottomToolbar: - onSendClick = { - if (inputText.isNotBlank()) { - onSend(inputText) - textFieldState.edit { replace(0, length, "") } - } - }, + onSendClick = doSend,Also applies to: 112-116
138-156: Remove unusedInputHintscomposable or mark with TODO.
InputHintsis defined but never referenced or rendered anywhere in the codebase. Either remove it or add a TODO comment if it's intended for future use.mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (1)
707-709: Emptyupdateblock provides no reactive updates.The
updatelambda is intended for updating the Swing component when Compose state changes, but it's currently empty. This is where you could update the Swing component's enabled state or sync state changes.update = { panel -> - // Update panel if needed + // Sync processing state to disable editor during execution + devInInput?.isEnabled = !isProcessing }mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (2)
8-8: Unused import.The
Colorimport fromandroidx.compose.ui.graphicsappears unused since all colors are obtained fromJewelThemeorAutoDevColors.
64-67: Consider using IntelliJ icons instead of emoji characters.Emoji characters (📁, ⚙, ⏹) may render inconsistently across platforms or font configurations. Consider using IntelliJ's
AllIconsor Jewel's icon components for a more consistent appearance within the IDE.Also applies to: 128-131
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt (2)
224-227: Redundanttext = ""afterrecreateDocument().The
recreateDocument()method creates a new document with empty content (""), so the subsequenttext = ""assignment is unnecessary.fun clearInput() { recreateDocument() - text = "" }
184-185: Consider graceful error handling instead of throwing.Throwing
IllegalStateExceptionif the document cannot be created will crash the UI. Consider logging an error and returning early, or using a fallback approach.val document = FileDocumentManager.getInstance().getDocument(file) - ?: throw IllegalStateException("Can't create in-memory document") + ?: run { + // Log error and keep existing document + com.intellij.openapi.diagnostic.Logger.getInstance(IdeaDevInInput::class.java) + .error("Failed to create in-memory document for DevIn input") + return + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputListener.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt(3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt
📄 CodeRabbit inference engine (AGENTS.md)
Use
expect/actualfor platform-specific code in KMP projects (e.g., file I/O on JVM/JS/Wasm)
Files:
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputListener.kt
🧠 Learnings (1)
📚 Learning: 2025-11-30T02:30:49.805Z
Learnt from: CR
Repo: phodal/auto-dev-sketch PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-30T02:30:49.805Z
Learning: Applies to **/src/{androidMain,desktopMain}/**/*.kt : For 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/IdeaAgentApp.kt
🧬 Code graph analysis (2)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (1)
IdeaBottomToolbar(22-161)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (2)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt (3)
recreateDocument(179-189)addInputListener(200-202)clearInput(224-227)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (1)
IdeaBottomToolbar(22-161)
⏰ 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 (4)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputListener.kt (1)
6-38: Well-designed listener interface with sensible defaults.The interface follows the IntelliJ platform convention of extending
EventListenerfor use withEventDispatcher, and default method implementations allow consumers to override only the events they care about.mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (2)
47-75: Project name extraction handles both path separators correctly.The chained
substringAfterLastcalls properly handle both Unix (/) and Windows (\) path separators with a sensible "Project" fallback.
134-158: Send/Stop button toggle implementation is clean.The conditional rendering based on
isExecutingprovides clear visual feedback, and the use ofAutoDevColorsaligns with the project's design system as per the learnings.mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt (1)
52-57: Enter submit action triggers even when editor is empty after trim.The submit action checks
text.trim().isNotEmpty()which is correct, but theonSubmitcallback receives the trimmed text. Ensure consumers expect trimmed input.
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt
Outdated
Show resolved
Hide resolved
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt
Show resolved
Hide resolved
| factory = { | ||
| val input = IdeaDevInInput( | ||
| project = project, | ||
| disposable = parentDisposable, | ||
| showAgent = true | ||
| ).apply { | ||
| recreateDocument() | ||
|
|
||
| addInputListener(object : IdeaInputListener { | ||
| override fun editorAdded(editor: EditorEx) { | ||
| // Editor is ready | ||
| } | ||
| true | ||
| } else { | ||
| false | ||
| } | ||
| }, | ||
| enabled = !isProcessing | ||
| ) | ||
|
|
||
| if (isProcessing) { | ||
| DefaultButton(onClick = onAbort) { | ||
| Text("Stop") | ||
| } | ||
| } else { | ||
| DefaultButton( | ||
| onClick = { | ||
| if (inputText.isNotBlank()) { | ||
| onSend(inputText) | ||
| textFieldState.edit { replace(0, length, "") } | ||
| } | ||
| }, | ||
| enabled = inputText.isNotBlank() | ||
| ) { | ||
| Text("Send") | ||
| override fun onSubmit(text: String, trigger: IdeaInputTrigger) { | ||
| if (text.isNotBlank() && !isProcessing) { | ||
| onSend(text) | ||
| clearInput() | ||
| inputText = "" | ||
| } | ||
| } | ||
|
|
||
| override fun onStop() { | ||
| onAbort() | ||
| } | ||
|
|
||
| override fun onTextChanged(text: String) { | ||
| inputText = text | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| // Register for disposal | ||
| Disposer.register(parentDisposable, input) | ||
| devInInput = input | ||
|
|
||
| // Wrap in a JPanel to handle sizing | ||
| JPanel(BorderLayout()).apply { | ||
| add(input, BorderLayout.CENTER) | ||
| preferredSize = Dimension(800, 120) | ||
| minimumSize = Dimension(200, 80) | ||
| } | ||
| }, | ||
| update = { panel -> | ||
| // Update panel if needed | ||
| } | ||
| } | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stale closure capture of isProcessing in SwingPanel factory.
The factory lambda runs only once when the SwingPanel is first composed. The IdeaInputListener created inside captures the initial value of isProcessing, which will never update. This means the !isProcessing check on line 679 will always reflect the initial state.
Consider one of these approaches:
- Move the processing check to the
onSendcallback and let the parent handle gating. - Use a
Refor mutable holder that can be updated from theupdateblock.
+ // Use a ref to avoid stale closure
+ val isProcessingRef = remember { mutableStateOf(isProcessing) }
+ LaunchedEffect(isProcessing) { isProcessingRef.value = isProcessing }
SwingPanel(
...
factory = {
val input = IdeaDevInInput(...).apply {
addInputListener(object : IdeaInputListener {
override fun onSubmit(text: String, trigger: IdeaInputTrigger) {
- if (text.isNotBlank() && !isProcessing) {
+ if (text.isNotBlank() && !isProcessingRef.value) {
onSend(text)
...
}
}
...
})
}
...
},Committable suggestion skipped: line range outside the PR's diff.
| IdeaBottomToolbar( | ||
| onSendClick = { | ||
| val text = devInInput?.text?.trim() ?: inputText.trim() | ||
| if (text.isNotBlank() && !isProcessing) { | ||
| onSend(text) | ||
| devInInput?.clearInput() | ||
| inputText = "" | ||
| } | ||
| }, | ||
| sendEnabled = inputText.isNotBlank() && !isProcessing, | ||
| isExecuting = isProcessing, | ||
| onStopClick = onAbort, | ||
| onAtClick = { | ||
| devInInput?.appendText("@") | ||
| onAtClick() | ||
| }, | ||
| onSettingsClick = onSettingsClick, | ||
| workspacePath = workspacePath, | ||
| totalTokens = totalTokens | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Send button enabled state inconsistent with editor submit behavior.
The sendEnabled check on line 722 uses inputText.isNotBlank(), but the button's onSendClick on line 715 also checks devInInput?.text. These could diverge if inputText state isn't perfectly synchronized with the editor's actual text. Consider using a single source of truth.
🤖 Prompt for AI Agents
In mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt
around lines 713 to 732, the send button enabled state uses
inputText.isNotBlank() while the onSendClick handler reads devInInput?.text,
which can diverge; unify to a single source of truth by computing a single
trimmed currentText (e.g. val currentText = devInInput?.text?.trim() ?:
inputText.trim()) and use that variable both for the sendEnabled boolean and
inside onSendClick (call onSend(currentText) and clear/reset state accordingly)
so the button state and submit behavior are always consistent.
- Fix memory leak by storing and properly disposing internal DocumentListener - Fix recreateDocument to use EditorFactory instead of FileDocumentManager - Re-attach listeners when document is recreated - Fix Windows path handling in project name extraction - Remove unused imports (Color, java.util.*) - Extract duplicate send logic to avoid code duplication - Remove redundant text assignment in clearInput() Addresses review comments from PR #7
Code Review Fixes Applied ✅I've addressed all the critical review comments from the automated code review: Memory Leak Fixes
Document Creation Fix
Code Quality Improvements
Files Changed
All changes have been pushed to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt (3)
43-48: LGTM on class structure and fields.The class properly extends
EditorTextFieldand implementsDisposable. TheshowAgentparameter is declared but unused — consider removing it if not needed for future functionality, or document its intended purpose.
76-94: Redundant command nesting.
WriteCommandAction.runWriteCommandActionalready wraps the action in a command. The outerCommandProcessor.getInstance().executeCommandis redundant.private fun insertNewLine(editor: Editor) { - CommandProcessor.getInstance().executeCommand(project, { - val eol = "\n" - val document = editor.document - val caretOffset = editor.caretModel.offset - val lineEndOffset = document.getLineEndOffset(document.getLineNumber(caretOffset)) - val textAfterCaret = document.getText(TextRange(caretOffset, lineEndOffset)) - - WriteCommandAction.runWriteCommandAction(project) { - if (textAfterCaret.isBlank()) { - document.insertString(caretOffset, eol) - EditorModificationUtil.moveCaretRelatively(editor, 1) - } else { - document.insertString(caretOffset, eol) - editor.caretModel.moveToOffset(caretOffset + eol.length) - } + val eol = "\n" + val document = editor.document + val caretOffset = editor.caretModel.offset + val lineEndOffset = document.getLineEndOffset(document.getLineNumber(caretOffset)) + val textAfterCaret = document.getText(TextRange(caretOffset, lineEndOffset)) + + WriteCommandAction.runWriteCommandAction(project, "Insert New Line", null, { + if (textAfterCaret.isBlank()) { + document.insertString(caretOffset, eol) + EditorModificationUtil.moveCaretRelatively(editor, 1) + } else { + document.insertString(caretOffset, eol) + editor.caretModel.moveToOffset(caretOffset + eol.length) } - }, "Insert New Line", null) + }) }
153-155: Consider defensive casting.The cast
editor as EditorExassumes the editor is always anEditorEx. While this is typically true in IntelliJ, a safe cast would be more defensive.override fun onEditorAdded(editor: Editor) { - editorListeners.multicaster.editorAdded(editor as EditorEx) + (editor as? EditorEx)?.let { editorListeners.multicaster.editorAdded(it) } }mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt (1)
93-107: Consider handling Alt+Enter modifier.The key event check excludes Shift, Ctrl, and Meta modifiers but not Alt. On some systems, Alt+Enter might be expected to behave like other modifier+Enter combinations (newline instead of submit).
if (keyEvent.key == Key.Enter && keyEvent.type == KeyEventType.KeyDown && !keyEvent.isShiftPressed && !keyEvent.isCtrlPressed && !keyEvent.isMetaPressed && + !keyEvent.isAltPressed && !isProcessing ) {mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (1)
110-133: Consider using proper icons instead of emoji characters.The emoji characters ("@", "⚙") may render inconsistently across different platforms and themes. Consider using IntelliJ's icon system or Jewel icons for consistent appearance.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputListener.kt(1 hunks)mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputListener.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt
📄 CodeRabbit inference engine (AGENTS.md)
Use
expect/actualfor platform-specific code in KMP projects (e.g., file I/O on JVM/JS/Wasm)
Files:
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.ktmpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt
🧬 Code graph analysis (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (1)
IdeaBottomToolbar(21-162)
⏰ 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 (223)
- GitHub Check: Build (241)
🔇 Additional comments (16)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt (8)
52-57: LGTM!The internal document listener is now properly stored as a field, enabling correct cleanup during disposal. This addresses the previous review feedback.
59-74: LGTM!The submit action correctly trims input and validates non-empty text before firing the submit event. The newline action safely handles null editor.
96-143: LGTM!The init block properly configures the editor settings, registers shortcuts for both submit and newline actions, and correctly integrates with the
LookupManagerListenerto prevent accidental submissions during completion popup display.
145-151: LGTM!Clean shortcut registration and unregistration pattern.
157-166: LGTM!The editor is properly configured with appropriate visual settings for the input use case.
173-178: LGTM!The dispose method now correctly removes both the internal document listener and external listeners, addressing the previous review feedback about potential memory leaks.
184-208: LGTM!The document recreation logic now properly removes listeners from the old document before replacing it and re-adds all listeners (including the internal one) to the new document. This correctly addresses the previous review feedback.
210-240: LGTM!The public API methods are well-documented and correctly implemented. The
appendTextmethod properly usesWriteCommandActionfor thread-safe document modifications.mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt (4)
34-44: LGTM!Well-documented composable with clear parameter descriptions. The default values for optional callbacks provide sensible fallbacks.
45-61: LGTM!The state synchronization pattern using
snapshotFlowwithdistinctUntilChangedis correct and efficient. ThedoSendlambda properly clears the input after submission.
115-130: LGTM!The toolbar integration is clean, with proper callback wiring. The
onAtClickhandler correctly appends the "@" character before invoking the callback.
137-155:InputHintsis defined but not used within this file.The
InputHintscomposable is defined here but not used withinIdeaInputSection. Verify this is intentional for external use, or consider integrating it into the input section if hints should be displayed.mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (4)
21-32: LGTM!Well-documented composable with sensible parameter defaults. The API surface is clean and focused.
47-76: Windows path handling is now correctly addressed.The path normalization using
replace('\\', '/')beforesubstringAfterLast('/')correctly handles both Unix and Windows path separators. This addresses the previous review feedback.
78-102: LGTM!The token usage indicator has proper null and zero-value checks with clean conditional rendering.
135-159: LGTM!The Send/Stop button toggle logic correctly responds to the
isExecutingstate, and the Send button properly respects thesendEnabledflag.
…jis with icons - Fix ClassCastException in AnalysisAgent by validating SubAgent input before creating invocation - Fix duplicate key error in LazyColumn by adding unique ID to TimelineItem - Replace all emojis with Material Design icons from AutoDevComposeIcons - Tool icon (Build) - Error icon (Error) - Success/Failure icons (CheckCircle/Error) - Settings icon (Settings) - Remove emoji from recovery advice and confirmation messages Fixes: - java.lang.ClassCastException: LinkedHashMap cannot be cast to ContentHandlerContext - IllegalArgumentException: Key was already used in LazyColumn
2203e15 to
72babb1
Compare
Additional Fixes AppliedAdded critical bug fixes and UI improvements: Bug Fixes1. ClassCastException in AnalysisAgentIssue: Root Cause: Solution: Added type checking and input validation for SubAgent: if (tool is SubAgent<*, *>) {
val validatedInput = subAgent.validateInput(params)
val invocation = subAgent.createInvocation(validatedInput)
return invocation.execute(context)
}2. Duplicate Key in LazyColumnIssue: Root Cause: Using Solution: Added unique ID generation to sealed class TimelineItem(val timestamp: Long, val id: String = generateId()) {
companion object {
private var idCounter = 0L
fun generateId(): String = "${System.currentTimeMillis()}-${idCounter++}"
}
}UI ImprovementsReplace Emojis with Material Design IconsReplaced all emojis with proper icons from
Benefits:
Files Changed
All tests should now pass without ClassCastException or duplicate key errors. |
Summary
Implement advanced input components for mpp-idea module with full DevIn language support.
Changes
New Components
Integration
DevInInputAreawith SwingPanelFeatures
References
Based on:
DevInEditorInput.ktfrom mpp-ui (Compose Multiplatform)AutoDevInput.ktfrom core (IntelliJ IDEA)Pull Request opened by Augment Code with guidance from the PR author
Summary by CodeRabbit
New Features
Improvements
API
✏️ Tip: You can customize this high-level summary in your review settings.