ArthurSonzogni/json-tui

Bug - does not line wrap very long components inside a nested block

avighnac opened this issue · 2 comments

I have tested this on latest bleeding edge version (pulled the source and compiled myself), and it, unfortunately, fails to display them correctly.

JSON file

test.json:

{
    "add_fraction": {
        "410316161936543210318350169581764580736439706176897187461658745638794056381701649193496832507908441/110671625084041270369510745874519827349056231468761863406526354819216040200965715245470578016585408 780107824732963918497386127905416971547624143459884572049407936047104618365218009083504802769369177/682940054189039580356617302601487398249912223437990021245684561942032321432853067545223611875328379": 2.485323
    }
}

Command

json-tui test.json

Without the nested { ... } as a value to the add_fraction key, it works as expected:
image

However, adding one makes the line wrapping functionality break,
image

I believe the problem is in two-places(within main_ui.cpp):

  1. Basic(...):
    auto element = paragraph(value) | color(c);
  2. FromKeyValue(...):
    text(str) | color(Color::BlueLight),

Referring to point 1: The key-values are represented as paragraphs. The paragraph function splits text at every word (i.e., at every space/" "). The JSON you supplied includes a single space, which accounts for why it wraps in the first image.

Referring to point 2: The keys are represented by the text() element, meaning they will extend off screen without wrapping, see your second image. This could be remedied by allowing the user to scroll horizontally (frame + focusPosition decorators).

My duct-tape solution to view the entire key was to simply split the string every 40 characters & add them to a flexbox. This still leaves a single problem, when the key is too long, it pushes the contents off screen, because it is using a horizontal box in the renderer of FromKeyValue()

Before expanding

image
After ### expanding
image

My very terrible implementation intended as a proof of concept

   60 Element wrapText(std::string input_string) {                                                      
   61         Elements split_string = {};
   62         if (input_string.length() > 40) {
   63                 size_t lastPos = 0;
   64                 size_t nextPos = 40;                                                              
   65                 while (nextPos != lastPos) {
   66                         split_string.push_back(text(input_string.substr(lastPos, nextPos))); ‣x: text(input_string.substr(lastPos, nextPos)) ‣text: input_string.substr(lastPos, nextPos
   67                         lastPos = nextPos;
   68                         nextPos = (input_string.length() - lastPos > 40) ? lastPos + 40 : input_string.length();
   69                 }
   70         }
   71         return flexbox(split_string);
   72 }

The Text class/decorator for reference

   19 class Text : public Node {
   20  public:
   21   explicit Text(std::string text) : text_(std::move(text)) {} ‣t: text                                                                                                                  
   22 
   23   void ComputeRequirement() override {
   24     requirement_.min_x = string_width(text_);
   25     requirement_.min_y = 1;
   26   }
   27 
   28   void Render(Screen& screen) override {
   29     int x = box_.x_min;
   30     const int y = box_.y_min;
   31     if (y > box_.y_max) {
   32       return;
   33     }
   34     for (const auto& cell : Utf8ToGlyphs(text_)) { ‣input: text_ ‣: basic_string<char> const &                                                                                          
   35       if (x > box_.x_max) {
   36         return;
   37       }
   38       screen.PixelAt(x, y).character = cell;
   39       ++x;
   40     }
   41   }
   42 
   43  private:
   44   std::string text_;
   45 };

The Paragraph & Split functions for reference:

   11 Elements Split(const std::string& the_text) {
   12   Elements output;
   13   std::stringstream ss(the_text); ‣str: the_text                                         
   14   std::string word;
   15   while (std::getline(ss, word, ' ')) { ‣in: ss ‣str: word ‣delim: ' '
   16     output.push_back(text(word)); ‣x: text(word) ‣text: word
   17   }
   18   return output;
   19 }
   20 }  // namespace                     
   22 /// @brief Return an element drawing the paragraph on multiple lines.
   25 Element paragraph(const std::string& the_text) {
   26   return paragraphAlignLeft(the_text); ‣text: the_text
   27 }                                                                                                                                                                                       
   33 Element paragraphAlignLeft(const std::string& the_text) {
   34   static const auto config = FlexboxConfig().SetGap(1, 0); ‣gap_x: 1 ‣gap_y: 0 ‣: const FlexboxConfig   
   35   return flexbox(Split(the_text), config);                                                                        
   36 }

Thanks for raising this issue!

I don't see any solution at the moment. I need take some time to think about it. Maybe we should add the ability to scroll horizontally.

It looks like Chrome/Devtool is not doing better:
image