clay icon indicating copy to clipboard operation
clay copied to clipboard

[Question] How do you handle long texts?

Open josegomezr opened this issue 9 months ago • 6 comments

I'm (ab-)using my C skills and this project to build a silly json viewer in the terminal

With questionable C/C++ choices and some PR's baked in I got to a point where I can render stuff and have an interactive-ish view experience.

But when opening a large json doc (more than 100kb) it dies with either:

  • ERR-1: Clay attempted to allocate memory in its arena, but ran out of capacity. Try increasing the capacity of the arena passed to Clay_Initialize()

  • ERR-3: Clay has run out of space in it's internal text measurement cache. Try using Clay_SetMaxMeasureTextCacheWordCount() (default 16384, with 1 unit storing 1 measured word).

If anybody dares to view my C/C++ disaster, have some coffee before and check it there:

https://github.com/josegomezr/clayson/blob/5931e6e08d1cefc9ddaa69d2ab4679aae9deeaae/main.c#L179-L184

The TL;DR goes like:

// assumption:
// - The window is 80x24 (1 col in the terminal => 1 px i guess?)
// - appstate.main_screen_buffer is malloc'd and free'd by me, they're containing a "pretty printed" json document (and it's length).
//   the heinous example that breaks with the errors above is a 19MB json document, so the buffer has 20 MB

typedef struct {
  char* main_screen_buffer;
  size_t main_screen_buffer_len;
  // [...]
} ApplicationState;

CLAY({
    .layout = {
      .layoutDirection = CLAY_TOP_TO_BOTTOM,
      .sizing = {
        .width = CLAY_SIZING_GROW(),
        .height = CLAY_SIZING_FIXED(400) // say is a big enough height
      }
    }
  }) {
    Clay_String str = (Clay_String) {
      .length = appstate->main_screen_buffer_len,
      .chars = appstate->main_screen_buffer
    };

    CLAY_TEXT(str, CLAY_TEXT_CONFIG({ .textColor = COLOR_WHITE }));
  }

Any ideas how to handle long pieces of text on a layout?

I must admit I tried to be more clever than the layout engine and only render like a "view" of the long buffer, and prepend newlines to compensate for the scroll but got me very inconsistent results 😅

josegomezr avatar Mar 22 '25 21:03 josegomezr

Clay_TextElementConfig {
    bool hashStringContents
}; 

I think you need to turn off hash string contents in this case.

Muzz avatar Mar 22 '25 23:03 Muzz

Clay_TextElementConfig {
    bool hashStringContents
}; 

Tried it with both true & false and failed with the same error msg.

josegomezr avatar Mar 23 '25 09:03 josegomezr

Hello 👋 Clay uses a fixed size memory arena to manage its memory, that you initialize and pass to it. By default, Clay will ask for enough memory to store about 8k UI elements, and about 16k cached words. Those limits are available here: https://github.com/nicbarker/clay/blob/main/clay.h#L987-L988

You can increase the limits by calling Clay_SetMaxElementCount and Clay_SetMaxMeasureTextCacheWordCount with higher than default numbers before calling Clay_MinMemorySize() and initializing your Arena 🙂

nicbarker avatar Mar 23 '25 20:03 nicbarker

[...] before calling Clay_MinMemorySize() and initializing your Arena 🙂

Achso! That would explain why I tried it and didn't notice an effect. Will test it out and report back with the results :)

josegomezr avatar Mar 24 '25 11:03 josegomezr

It "progressed" (in the sense of getting a different error message), tweaked them as high as I could but got only repeated instances of:

./main ../SUSE/esbom/_testdata/reference.sles.x86_64-15.4-kvm.spdx.json
Allocating 438310336 bytes
ERR-1: Clay attempted to allocate memory in its arena, but ran out of capacity. Try increasing the capacity of the arena passed to Clay_Initialize()

And funnily enough once:

./main ../SUSE/esbom/_testdata/reference.sles.x86_64-15.4-kvm.spdx.json
Floating point exception (core dumped)

I may need to rethink my strategy here 😅

josegomezr avatar Mar 24 '25 22:03 josegomezr

I will investigate rendering a huge number of text elements and see if there are any dragons lurking there 🙂

nicbarker avatar Mar 25 '25 20:03 nicbarker