JakeWharton / mosaic

Build terminal UI in Kotlin using Jetpack Compose
Apache License 2.0
1.96k stars 57 forks source link

`ArrayIndexOutOfBoundsException` when rerendering long text #426

Open hbmartin opened 3 months ago

hbmartin commented 3 months ago

There appears to be some issues when rendering Text that exceeds the canvas size - I've reproduced the issue from within both Box and Column. I've tried both with and without a color parameter but seeing the same result.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 238 out of bounds for length 238 at com.jakewharton.mosaic.TextSurface.get(canvas.kt:38) at com.jakewharton.mosaic.layout.TextCanvasDrawScope.drawText-hS_falQ(DrawScope.kt:115) at com.jakewharton.mosaic.layout.TextCanvasDrawScope.drawText-8Xo7vWM(DrawScope.kt:87) at com.jakewharton.mosaic.ui.Text.Text_GddN7rU$lambda$5$lambda$4(Text.kt:36) at com.jakewharton.mosaic.layout.DrawBehindElement.draw(DrawModifier.kt:36) at com.jakewharton.mosaic.layout.DrawLayer.drawTo(Node.kt:249) at com.jakewharton.mosaic.layout.AbstractMosaicNodeLayer.drawTo(Node.kt:62) at com.jakewharton.mosaic.layout.BottomLayer.drawTo(Node.kt:188) at com.jakewharton.mosaic.layout.AbstractMosaicNodeLayer.drawTo(Node.kt:62) at com.jakewharton.mosaic.layout.AbstractMosaicNodeLayer.drawTo(Node.kt:62) at com.jakewharton.mosaic.layout.DrawLayer$drawTo$scope$1.drawContent(Node.kt:246) at me.haroldmartin.objective.cli.common.BorderModifier.draw(Border.kt:64) at com.jakewharton.mosaic.layout.DrawLayer.drawTo(Node.kt:249) at com.jakewharton.mosaic.layout.AbstractMosaicNodeLayer.drawTo(Node.kt:62) at com.jakewharton.mosaic.layout.BottomLayer.drawTo(Node.kt:188) at com.jakewharton.mosaic.layout.AbstractMosaicNodeLayer.drawTo(Node.kt:62) at com.jakewharton.mosaic.layout.AbstractMosaicNodeLayer.drawTo(Node.kt:62) at com.jakewharton.mosaic.layout.BottomLayer.drawTo(Node.kt:188) at com.jakewharton.mosaic.layout.DrawLayer$drawTo$scope$1.drawContent(Node.kt:246) at com.jakewharton.mosaic.layout.BackgroundModifier.draw(Background.kt:21) at com.jakewharton.mosaic.layout.DrawLayer.drawTo(Node.kt:249) at com.jakewharton.mosaic.layout.AbstractMosaicNodeLayer.drawTo(Node.kt:62) at com.jakewharton.mosaic.layout.AbstractMosaicNodeLayer.drawTo(Node.kt:62) at com.jakewharton.mosaic.layout.BottomLayer.drawTo(Node.kt:188) at com.jakewharton.mosaic.layout.MosaicNode.paint(Node.kt:141) at com.jakewharton.mosaic.AnsiRendering.render(rendering.kt:108) at com.jakewharton.mosaic.MosaicKt$runMosaic$2.invokeSuspend$lambda$1(mosaic.kt:79) at com.jakewharton.mosaic.MosaicNodeApplier.onEndChanges(mosaic.kt:188) at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:978) at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:1005) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:639) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:551) at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42) at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71) at com.jakewharton.mosaic.MosaicKt$runMosaic$2$2.invokeSuspend(mosaic.kt:96) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:231) at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:164) at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:466) at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:500) at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:489) at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:587) at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:490) at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:277) at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:95) at kotlinx.coroutines.BuildersKtBuildersKt.runBlocking(Builders.kt:69) at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source) at kotlinx.coroutines.BuildersKtBuildersKt.runBlocking$default(Builders.kt:48) at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source) at com.jakewharton.mosaic.BlockingKt.runMosaicBlocking(blocking.kt:6) at me.haroldmartin.objective.cli.MainKt.main(Main.kt:9)

EpicDima commented 3 months ago

I reproduced it. This is quite expected, since we are not doing anything with the text now when we have a limited size (in this case, width), so it goes beyond the boundaries of the element that were measured earlier.

I think we need to do something with the text, probably add measurement, layout and placement logic.

Specifically, the crash will be fixed at 255.