@@ -7,43 +7,45 @@ import androidx.compose.foundation.background
77import androidx.compose.foundation.clickable
88import androidx.compose.foundation.interaction.MutableInteractionSource
99import androidx.compose.foundation.layout.*
10- import androidx.compose.foundation.rememberScrollState
1110import androidx.compose.foundation.shape.RoundedCornerShape
12- import androidx.compose.foundation.verticalScroll
1311import androidx.compose.runtime.*
1412import androidx.compose.ui.Alignment
1513import androidx.compose.ui.Modifier
1614import androidx.compose.ui.draw.clip
17- import androidx.compose.ui.graphics.Color
1815import androidx.compose.ui.text.font.FontFamily
1916import androidx.compose.ui.text.font.FontWeight
2017import androidx.compose.ui.unit.dp
2118import androidx.compose.ui.unit.sp
2219import cc.unitmesh.agent.render.TimelineItem
20+ import cc.unitmesh.devins.idea.renderer.terminal.IdeaAnsiTerminalRenderer
21+ import cc.unitmesh.devins.idea.terminal.TerminalApiCompat
2322import cc.unitmesh.devins.idea.toolwindow.IdeaComposeIcons
2423import cc.unitmesh.devins.ui.compose.theme.AutoDevColors
2524import com.intellij.openapi.ide.CopyPasteManager
25+ import com.intellij.openapi.project.Project
2626import org.jetbrains.jewel.foundation.theme.JewelTheme
2727import org.jetbrains.jewel.ui.component.Icon
2828import org.jetbrains.jewel.ui.component.Text
2929import java.awt.datatransfer.StringSelection
3030
3131/* *
3232 * Terminal output bubble for displaying shell command results.
33- * Shows output with scrollable area (4 lines visible), full width layout.
33+ * Uses Jewel-themed ANSI terminal renderer for proper color and formatting support.
34+ * Shows output with scrollable area, full width layout.
35+ *
36+ * Features:
37+ * - ANSI color and formatting support
38+ * - Collapsible output with header
39+ * - Copy to clipboard
40+ * - Open in native terminal (when available)
3441 */
3542@Composable
3643fun IdeaTerminalOutputBubble (
3744 item : TimelineItem .TerminalOutputItem ,
38- modifier : Modifier = Modifier
45+ modifier : Modifier = Modifier ,
46+ project : Project ? = null
3947) {
4048 var expanded by remember { mutableStateOf(true ) }
41- val scrollState = rememberScrollState()
42-
43- // Auto-scroll to bottom when output changes
44- LaunchedEffect (item.output) {
45- scrollState.animateScrollTo(scrollState.maxValue)
46- }
4749
4850 Box (
4951 modifier = modifier
@@ -61,52 +63,46 @@ fun IdeaTerminalOutputBubble(
6163 onExpandToggle = { expanded = ! expanded },
6264 onCopy = {
6365 CopyPasteManager .getInstance().setContents(StringSelection (item.output))
66+ },
67+ onOpenInTerminal = project?.let { proj ->
68+ { openCommandInTerminal(proj, item.command) }
6469 }
6570 )
6671
67- // Collapsible output content with scrolling
72+ // Collapsible output content using Jewel ANSI terminal renderer
6873 AnimatedVisibility (
6974 visible = expanded,
7075 enter = expandVertically(),
7176 exit = shrinkVertically()
7277 ) {
73- Box (
78+ // Use Jewel-themed ANSI terminal renderer
79+ IdeaAnsiTerminalRenderer (
80+ ansiText = item.output,
7481 modifier = Modifier
7582 .fillMaxWidth()
76- .heightIn(max = 120 .dp) // ~4 lines at 12sp + padding
77- .background(Color (0xFF1E1E1E ))
78- .padding(12 .dp)
79- ) {
80- if (item.output.isNotEmpty()) {
81- Text (
82- text = item.output,
83- style = JewelTheme .defaultTextStyle.copy(
84- fontSize = 12 .sp,
85- fontFamily = FontFamily .Monospace ,
86- color = AutoDevColors .Neutral .c300,
87- lineHeight = 18 .sp
88- ),
89- modifier = Modifier .verticalScroll(scrollState)
90- )
91- } else {
92- Text (
93- text = " (No output)" ,
94- style = JewelTheme .defaultTextStyle.copy(
95- fontSize = 12 .sp,
96- fontFamily = FontFamily .Monospace ,
97- color = AutoDevColors .Neutral .c500
98- )
99- )
100- }
101- }
83+ .heightIn(min = 80 .dp, max = 300 .dp),
84+ maxHeight = 300 ,
85+ backgroundColor = AutoDevColors .Neutral .c900
86+ )
10287 }
10388 }
10489 }
10590}
10691
92+ /* *
93+ * Opens the command in IDEA's native terminal using compatibility layer.
94+ */
95+ private fun openCommandInTerminal (project : Project , command : String ) {
96+ TerminalApiCompat .openCommandInTerminal(
97+ project = project,
98+ command = command,
99+ tabName = " AutoDev: $command " ,
100+ requestFocus = true
101+ )
102+ }
107103
108104/* *
109- * Header component for terminal bubble with command, status, and copy button .
105+ * Header component for terminal bubble with command, status, and action buttons .
110106 */
111107@Composable
112108private fun TerminalHeader (
@@ -115,7 +111,8 @@ private fun TerminalHeader(
115111 executionTimeMs : Long ,
116112 expanded : Boolean ,
117113 onExpandToggle : () -> Unit ,
118- onCopy : () -> Unit
114+ onCopy : () -> Unit ,
115+ onOpenInTerminal : (() -> Unit )? = null
119116) {
120117 Row (
121118 modifier = Modifier
@@ -152,7 +149,7 @@ private fun TerminalHeader(
152149 )
153150
154151 // Command text (truncated if too long)
155- val displayCommand = if (command.length > 60 ) command.take(60 ) + " ..." else command
152+ val displayCommand = if (command.length > 50 ) command.take(50 ) + " ..." else command
156153 Text (
157154 text = " $ $displayCommand " ,
158155 style = JewelTheme .defaultTextStyle.copy(
@@ -164,14 +161,33 @@ private fun TerminalHeader(
164161 )
165162 }
166163
167- // Right side: Status and copy
164+ // Right side: Status and actions
168165 Row (
169166 horizontalArrangement = Arrangement .spacedBy(8 .dp),
170167 verticalAlignment = Alignment .CenterVertically
171168 ) {
172169 // Status badge
173170 TerminalStatusBadge (exitCode = exitCode, executionTimeMs = executionTimeMs)
174171
172+ // Open in terminal button (if available)
173+ if (onOpenInTerminal != null ) {
174+ Box (
175+ modifier = Modifier
176+ .size(24 .dp)
177+ .clip(RoundedCornerShape (4 .dp))
178+ .background(AutoDevColors .Neutral .c700)
179+ .clickable { onOpenInTerminal() },
180+ contentAlignment = Alignment .Center
181+ ) {
182+ Icon (
183+ imageVector = IdeaComposeIcons .Terminal ,
184+ contentDescription = " Open in Terminal" ,
185+ tint = AutoDevColors .Neutral .c300,
186+ modifier = Modifier .size(14 .dp)
187+ )
188+ }
189+ }
190+
175191 // Copy button
176192 Box (
177193 modifier = Modifier
@@ -206,6 +222,7 @@ private fun TerminalStatusBadge(
206222 AutoDevColors .Green .c400,
207223 " exit: 0 ${executionTimeMs} ms"
208224 )
225+
209226 else -> Triple (
210227 AutoDevColors .Red .c600.copy(alpha = 0.3f ),
211228 AutoDevColors .Red .c400,
@@ -228,4 +245,3 @@ private fun TerminalStatusBadge(
228245 )
229246 }
230247}
231-
0 commit comments