package cc.unitmesh.devins.ui.compose.sketch import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp /** * 渲染代码块 * 在 JVM 和 Android 平台使用 FiraCode 字体 */ @Composable fun CodeBlockRenderer( code: String, language: String, displayName: String = language ) { // Load FiraCode font with fallback to default monospace val codeFontFamily = remember { try { getFiraCodeFontFamily() } catch (e: Exception) { FontFamily.Monospace } } Card( modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(8.dp), colors = CardDefaults.cardColors( containerColor = MaterialTheme.colorScheme.surfaceVariant ) ) { Column( modifier = Modifier .fillMaxWidth() .padding(12.dp) ) { if (displayName.isNotEmpty() && displayName != "markdown") { Text( text = displayName, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.primary, modifier = Modifier.padding(bottom = 8.dp) ) } SelectionContainer { Text( text = code, style = MaterialTheme.typography.bodyMedium.copy( fontFamily = codeFontFamily ), color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.fillMaxWidth() ) } } } }