generated from JetBrains/intellij-platform-plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 471
Closed
Description
Problem
The current NanoRenderer<T> interface design makes it difficult to ensure complete cross-platform component implementation:
Current Implementation Issues
-
Generic render dispatch via
whenstatement:- Both
HtmlRendererandComposeNanoRendereruse awhen (ir.type)pattern to dispatch rendering - This relies on string matching (
"VStack","Card", etc.) which has no compile-time safety
- Both
-
Silent failures with
elsebranch:// HtmlRenderer.kt override fun renderComponent(ir: NanoIR): String { return when (ir.type) { "Component" -> renderComponentNode(ir) "VStack" -> renderVStack(ir) // ... more cases else -> "<!-- Unknown component: ${ir.type} -->" // Silent failure! } } // ComposeNanoRenderer.kt when (ir.type) { // ... cases else -> RenderUnknown(ir, modifier) // Silent failure! }
-
No compiler help for missing implementations:
- When adding a new component (e.g.,
TextArea,Select,Form), there is no compiler error if a renderer does not implement it - Developers must manually check all renderer implementations
- When adding a new component (e.g.,
Proposed Solution
Follow the pattern used in CodingAgentRenderer, which defines specific methods for each operation:
interface CodingAgentRenderer {
fun renderIterationHeader(current: Int, max: Int)
fun renderLLMResponseStart()
fun renderLLMResponseChunk(chunk: String)
fun renderToolCall(toolName: String, paramsStr: String)
fun renderToolResult(...)
fun renderError(message: String)
// ... each operation has its own method
}Proposed New Interface
/**
* Component-specific NanoUI Renderer interface
*
* Each component type has its own render method, ensuring compile-time
* checking when new components are added.
*/
interface NanoRenderer<T> {
// Full document rendering
fun render(ir: NanoIR): T
// Layout components
fun renderVStack(ir: NanoIR): T
fun renderHStack(ir: NanoIR): T
// Container components
fun renderCard(ir: NanoIR): T
fun renderForm(ir: NanoIR): T
// Content components
fun renderText(ir: NanoIR): T
fun renderImage(ir: NanoIR): T
fun renderBadge(ir: NanoIR): T
fun renderDivider(ir: NanoIR): T
// Input components
fun renderButton(ir: NanoIR): T
fun renderInput(ir: NanoIR): T
fun renderCheckbox(ir: NanoIR): T
fun renderTextArea(ir: NanoIR): T
fun renderSelect(ir: NanoIR): T
// Control flow
fun renderConditional(ir: NanoIR): T
fun renderForLoop(ir: NanoIR): T
// Component wrapper
fun renderComponent(ir: NanoIR): T
// Unknown/unsupported component handling
fun renderUnknown(ir: NanoIR): T
}Benefits
- Compile-time safety: Adding a new component to the interface immediately shows errors in all implementations
- Explicit contract: Clear which components each platform must support
- Discoverable: Easy to see which components need implementation
- Default implementations possible: Can provide sensible defaults for optional components
Files to Update
Core Interface
xuiper-ui/src/main/kotlin/cc/unitmesh/xuiper/render/NanoRenderer.kt- Add component-specific methods
Implementations
xuiper-ui/src/main/kotlin/cc/unitmesh/xuiper/render/HtmlRenderer.kt- Implement new interfacempp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/nano/ComposeNanoRenderer.kt- Implement new interface
Components to Support
Based on NanoSpecV1:
- Layout: VStack, HStack
- Container: Card, Form
- Content: Text, Image, Badge, Divider
- Input: Button, Input, Checkbox, TextArea, Select
- Control Flow: Conditional (if), ForLoop (for)
- Meta: Component (wrapper)
Alternative Approach (Sealed Interface)
Could also consider a sealed interface approach with visitor pattern, but the explicit method approach is simpler and matches the existing CodingAgentRenderer pattern.
Related Code References
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/CodingAgentRenderer.kt- Example of method-per-operation patternxuiper-ui/src/main/kotlin/cc/unitmesh/xuiper/spec/v1/NanoSpecV1.kt- Component definitions
Metadata
Metadata
Assignees
Labels
No labels