Sfoglia il codice sorgente

Merge branch 'devel'

B Thibault 9 anni fa
parent
commit
63f32656d3

+ 10 - 1
include/curseOutput.hh

@@ -60,6 +60,11 @@ class CurseOutput
         **/
         virtual void shutdown() =0;
 
+        /**
+         * Called before redraw after window got SIGWINCH'd
+        **/
+        virtual void onResizeHandler();
+
         /**
          * return false if bottom of screen is touched
          * redraw all data
@@ -92,10 +97,12 @@ class CurseOutput
         virtual inputResult nextResult() =0;
         virtual inputResult changeWindow(char direction, bool cycle) =0;
 
+        virtual bool hasReachedBottom(unsigned int pos, unsigned int scrollTop, unsigned int maxHeight) const;
+
         /**
          * get the screen size
         **/
-        virtual const t_Cursor getScreenSize() const;
+        virtual const t_Cursor getScreenSize() const =0;
         const t_Cursor getScreenSizeUnsafe() const;
 
         /**
@@ -180,6 +187,8 @@ class CurseOutput
         **/
         std::set<char /* OutputFlag::TYPE_SOMETHING */> colors;
 
+        t_Cursor screenSize;
+
         class SelectionOutOfRange { };
 };
 

+ 7 - 6
include/curseSimpleOutput.hh

@@ -30,6 +30,7 @@ class CurseSimpleOutput: public CurseOutput
         **/
         void shutdown();
 
+        const t_Cursor getScreenSize() const;
         /**
          * get flags to be passed to write.
          * Contains indications on who to write item
@@ -40,12 +41,12 @@ class CurseSimpleOutput: public CurseOutput
         unsigned int write(const int &x, const int &y, const char item, unsigned int maxWidth, OutputFlag flags);
         unsigned int write(const int &x, const int &y, const std::string &str, const size_t strlen, unsigned int maxWidth, const OutputFlag flags);
         void write(const std::string &str, const OutputFlag flags) const;
-        bool writeKey(const std::string &key, const size_t keylen, t_Cursor &cursor, const t_Cursor &maxWidth, OutputFlag, unsigned int extraLen =0);
-        bool writeKey(const std::string &key, const size_t keylen, const std::string &after, size_t afterlen, t_Cursor &cursor, const t_Cursor &maxSize, OutputFlag flags);
-        bool writeKey(const std::string &key, const size_t keylen, const std::string &after, t_Cursor &cursor, const t_Cursor &maxWidth, OutputFlag);
-        bool writeContainer(t_Cursor &, const t_Cursor &maxSize, const JSonContainer *);
-        bool writeContent(t_Cursor &cursor, const t_Cursor &maxSize, std::list<JSonElement *> * obj);
-        bool redraw(t_Cursor &, const t_Cursor &, JSonElement *);
+        bool writeKey(const std::string &key, const size_t keylen, t_Cursor &cursor, OutputFlag, unsigned int extraLen =0);
+        bool writeKey(const std::string &key, const size_t keylen, const std::string &after, size_t afterlen, t_Cursor &cursor, OutputFlag flags);
+        bool writeKey(const std::string &key, const size_t keylen, const std::string &after, t_Cursor &cursor, OutputFlag);
+        bool writeContainer(t_Cursor &, const JSonContainer *);
+        bool writeContent(t_Cursor &cursor, std::list<JSonElement *> * obj);
+        bool redraw(t_Cursor &, JSonElement *);
         void checkSelection(const JSonElement *item, const t_Cursor &cursor);
 
     protected:

+ 10 - 9
include/curseSplitOutput.hh

@@ -37,17 +37,17 @@ class CurseSplitOutput: public CurseOutput
         void checkSelection(const JSonElement *item);
 
         bool redraw();
-        bool redraw(t_subWindow &, const t_Cursor &screenSize, std::pair<int, JSonContainer *> &);
-        bool redraw(t_subWindow &, const t_Cursor &screenSize, JSonElement *);
-        const Optional<bool> redrawOneItemToWorkingWin(t_subWindow &w, const t_Cursor &);
+        bool redraw(t_subWindow &, std::pair<int, JSonContainer *> &);
+        bool redraw(t_subWindow &, JSonElement *);
+        const Optional<bool> redrawOneItemToWorkingWin(t_subWindow &w);
         bool isAdded(const std::pair<int, JSonContainer *> &) const;
         bool isAdded(const JSonElement *e) const;
 
-        bool writeContainer(const t_Cursor &maxSize, JSonContainer *, bool opening = true);
-        bool writeObjectEntry(t_subWindow &w, const t_Cursor &maxSize, JSonObjectEntry *item);
-        bool writeKey(t_subWindow &, const std::string &key, const size_t keylen, const t_Cursor &maxSize, OutputFlag flags, unsigned int extraLen =0);
-        bool writeKey(t_subWindow &, const std::string &key, const size_t keylen, const std::string &after, const size_t afterlen, t_Cursor &cursor, const t_Cursor &maxWidth, OutputFlag);
-        bool writeKey(t_subWindow &, const std::string &key, const size_t keylen, const std::string &after, t_Cursor &cursor, const t_Cursor &maxWidth, OutputFlag);
+        bool writeContainer(JSonContainer *, bool opening = true);
+        bool writeObjectEntry(t_subWindow &w, JSonObjectEntry *item);
+        bool writeKey(t_subWindow &, const std::string &key, const size_t keylen, OutputFlag flags, unsigned int extraLen =0);
+        bool writeKey(t_subWindow &, const std::string &key, const size_t keylen, const std::string &after, const size_t afterlen, t_Cursor &cursor, OutputFlag);
+        bool writeKey(t_subWindow &, const std::string &key, const size_t keylen, const std::string &after, t_Cursor &cursor, OutputFlag);
         unsigned int write(const int &x, const int &y, const char item, unsigned int maxWidth, OutputFlag flags);
         unsigned int write(const int &x, const int &y, const std::string &str, const size_t strlen, unsigned int maxWidth, const OutputFlag flags);
         void write(const std::string &str, const OutputFlag flags) const;
@@ -90,6 +90,8 @@ class CurseSplitOutput: public CurseOutput
         inputResult nextResult();
         inputResult changeWindow(char, bool);
 
+        void onResizeHandler();
+
         void setSelection(const JSonElement *);
 
         void computeDiff();
@@ -104,7 +106,6 @@ class CurseSplitOutput: public CurseOutput
          * Viewport start
         **/
         unsigned short nbInputs, selectedWin, workingWin;
-
         // TODO t_subWindow &workingSubwin, &selectedSubwin ??
 };
 

+ 1 - 1
include/streamConsumer.hh

@@ -60,7 +60,7 @@ class StreamConsumer
         JSonElement *consumeString(JSonContainer *parent, std::stringstream &buf);
         JSonElement *consumeBool(JSonContainer *parent, std::stringstream &buf, char c);
         JSonElement *consumeNumber(JSonContainer *parent, std::stringstream &buf, char c);
-        JSonElement *consumeNull(JSonContainer *parent, std::stringstream &buf);
+        JSonElement *consumeNull(JSonContainer *parent, std::stringstream &buf, char firstChar);
         bool consumeEscapedChar(char c, std::stringstream &buf);
 
         /**

+ 24 - 3
src/curseOutput.cpp

@@ -29,7 +29,11 @@ CurseOutput::CurseOutput(const Params &p): params(p)
 
 CurseOutput::~CurseOutput()
 {
+    struct winsize size;
+
     runningInst = nullptr;
+    if (ioctl(fileno(screen_fd ? screen_fd : stdout), TIOCGWINSZ, &size) == 0)
+        resize_term(size.ws_row, size.ws_col);
 }
 
 void CurseOutput::loop(WINDOW * w)
@@ -44,19 +48,34 @@ void CurseOutput::loop(WINDOW * w)
     } while (read != inputResult::quit);
 }
 
+void CurseOutput::onResizeHandler()
+{
+    clear();
+}
+
 bool CurseOutput::onsig(int signo)
 {
     struct winsize size;
+    t_Cursor oldScrSize;
 
     switch (signo)
     {
     case SIGWINCH:
         if (ioctl(fileno(screen_fd ? screen_fd : stdout), TIOCGWINSZ, &size) == 0)
             resize_term(size.ws_row, size.ws_col);
-        clear();
+        screenSize = getScreenSize();
+        onResizeHandler();
         while (!redraw());
         break;
 
+    case SIGCONT:
+        oldScrSize = getScreenSizeUnsafe();
+        if (ioctl(fileno(screen_fd ? screen_fd : stdout), TIOCGWINSZ, &size) == -1)
+            break;
+        if (size.ws_row != oldScrSize.second || size.ws_col != oldScrSize.first)
+            kill(getpid(), SIGWINCH);
+        break;
+
     case SIGKILL:
     case SIGINT:
     case SIGTERM:
@@ -156,9 +175,9 @@ unsigned int CurseOutput::getNbLines(const size_t nbChar, unsigned int maxWidth)
     return nLine +1;
 }
 
-const t_Cursor CurseOutput::getScreenSize() const
+bool CurseOutput::hasReachedBottom(unsigned int pos, unsigned int scrollTop, unsigned int height) const
 {
-    return getScreenSizeUnsafe();
+    return (pos >= scrollTop && (pos -scrollTop) > height -1);
 }
 
 const t_Cursor CurseOutput::getScreenSizeUnsafe() const
@@ -280,6 +299,7 @@ void CurseOutput::init()
     noecho();
     curs_set(false);
     keypad(stdscr, true);
+    screenSize = getScreenSize();
 
     if (params.colorEnabled())
     {
@@ -309,5 +329,6 @@ void CurseOutput::init()
     signal(SIGINT, _resizeFnc);
     signal(SIGTERM, _resizeFnc);
     signal(SIGKILL, _resizeFnc);
+    signal(SIGCONT, _resizeFnc);
 }
 

+ 38 - 30
src/curseSimpleOutput.cpp

@@ -34,7 +34,6 @@ void CurseSimpleOutput::run(JSonElement *root, const std::string &i)
 
 bool CurseSimpleOutput::redraw()
 {
-    const t_Cursor screenSize = getScreenSize();
     t_Cursor cursor(0, 1);
     /**
      * Will be true if the json's last item is visible
@@ -46,7 +45,7 @@ bool CurseSimpleOutput::redraw()
     clear();
     writeTopLine(inputName, OutputFlag::SPECIAL_ACTIVEINPUTNAME);
     try {
-        result = redraw(cursor, screenSize, data);
+        result = redraw(cursor, data);
     }
     catch (SelectionOutOfRange &e)
     {
@@ -191,24 +190,24 @@ inputResult CurseSimpleOutput::changeWindow(char, bool)
     return inputResult::nextInput;
 }
 
-bool CurseSimpleOutput::redraw(t_Cursor &cursor, const t_Cursor &maxSize, JSonElement *item)
+bool CurseSimpleOutput::redraw(t_Cursor &cursor, JSonElement *item)
 {
     checkSelection(item, cursor);
     if (dynamic_cast<const JSonContainer*>(item))
     {
-        if (!writeContainer(cursor, maxSize, (const JSonContainer *) item))
+        if (!writeContainer(cursor, (const JSonContainer *) item))
             return false;
     }
     else
     {
-        cursor.second += CurseOutput::write(cursor.first, cursor.second, item, maxSize.first, CurseSimpleOutput::getFlag(item));
-        if (cursor.second - scrollTop > 0 && (cursor.second - scrollTop) > maxSize.second -1)
+        cursor.second += CurseOutput::write(cursor.first, cursor.second, item, screenSize.first, CurseSimpleOutput::getFlag(item));
+        if (hasReachedBottom(cursor.second, scrollTop, screenSize.second))
             return false;
     }
     return true;
 }
 
-bool CurseSimpleOutput::writeContainer(t_Cursor &cursor, const t_Cursor &maxSize, const JSonContainer *item)
+bool CurseSimpleOutput::writeContainer(t_Cursor &cursor, const JSonContainer *item)
 {
     char childDelimiter[2];
 
@@ -221,21 +220,21 @@ bool CurseSimpleOutput::writeContainer(t_Cursor &cursor, const t_Cursor &maxSize
     {
         std::string ss;
         ss.append(&childDelimiter[0], 1).append(" ... ").append(&childDelimiter[1], 1);
-        cursor.second += write(cursor.first, cursor.second, ss, 7, maxSize.first, CurseSimpleOutput::getFlag(item));
+        cursor.second += write(cursor.first, cursor.second, ss, 7, screenSize.first, CurseSimpleOutput::getFlag(item));
     }
     else
     {
-        cursor.second += write(cursor.first, cursor.second, childDelimiter[0], maxSize.first, CurseSimpleOutput::getFlag(item));
-        if (cursor.second <= scrollTop && cursor.second > maxSize.second +scrollTop -1)
+        cursor.second += write(cursor.first, cursor.second, childDelimiter[0], screenSize.first, CurseSimpleOutput::getFlag(item));
+        if (hasReachedBottom(cursor.second, scrollTop, screenSize.second))
                 return false;
-        if (!writeContent(cursor, maxSize, (std::list<JSonElement *> *)item))
+        if (!writeContent(cursor, (std::list<JSonElement *> *)item))
             return false;
-        cursor.second += write(cursor.first, cursor.second, childDelimiter[1], maxSize.first, CurseSimpleOutput::getFlag(item));
+        cursor.second += write(cursor.first, cursor.second, childDelimiter[1], screenSize.first, CurseSimpleOutput::getFlag(item));
     }
-    return (cursor.second >= scrollTop || (cursor.second - scrollTop) <= maxSize.second -1);
+    return !hasReachedBottom(cursor.second, scrollTop, screenSize.second);
 }
 
-bool CurseSimpleOutput::writeContent(t_Cursor &cursor, const t_Cursor &maxSize, std::list<JSonElement*> *_item)
+bool CurseSimpleOutput::writeContent(t_Cursor &cursor, std::list<JSonElement*> *_item)
 {
     JSonContainer *item = (JSonContainer *)_item;
     bool containerIsObject = (dynamic_cast<JSonObject *>(item) != nullptr);
@@ -255,37 +254,42 @@ bool CurseSimpleOutput::writeContent(t_Cursor &cursor, const t_Cursor &maxSize,
             {
                 if (dynamic_cast<JSonObject *>(**ent))
                 {
-                    if (!writeKey(key, ent->lazystrlen(), "{ ... }", cursor, maxSize, CurseSimpleOutput::getFlag(ent)) || (cursor.second - scrollTop > 0 && (cursor.second - scrollTop) > maxSize.second -1))
+                    if (!writeKey(key, ent->lazystrlen(), "{ ... }", cursor, CurseSimpleOutput::getFlag(ent)))
                         break;
                 }
-                else if (!writeKey(key, ent->lazystrlen(), "[ ... ]", cursor, maxSize, CurseSimpleOutput::getFlag(ent)) || (cursor.second - scrollTop > 0 && (cursor.second - scrollTop) > maxSize.second -1))
+                else if (!writeKey(key, ent->lazystrlen(), "[ ... ]", cursor, CurseSimpleOutput::getFlag(ent)))
+                    break;
+                if (hasReachedBottom(cursor.second, scrollTop, screenSize.second))
                     break;
             }
             else if (!isContainer)
             {
                 JSonElement *eContent = **ent;
-                if (!writeKey(key, ent->lazystrlen(), eContent->stringify(), eContent->lazystrlen(), cursor, maxSize, CurseSimpleOutput::getFlag(ent)) || (cursor.second - scrollTop > 0 && (cursor.second - scrollTop) > maxSize.second -1))
+                if (!writeKey(key, ent->lazystrlen(), eContent->stringify(), eContent->lazystrlen(), cursor, CurseSimpleOutput::getFlag(ent))
+                        || hasReachedBottom(cursor.second, scrollTop, screenSize.second))
                     break;
             }
             else if (((JSonContainer*)(**ent))->size() == 0)
             {
                 if (dynamic_cast<const JSonObject *>(**ent) )
                 {
-                    if (!writeKey(key, ent->lazystrlen(), "{ }", cursor, maxSize, CurseSimpleOutput::getFlag(ent)) || (cursor.second - scrollTop > 0 && (cursor.second - scrollTop) > maxSize.second -1))
+                    if (!writeKey(key, ent->lazystrlen(), "{ }", cursor, CurseSimpleOutput::getFlag(ent)))
                         break;
                 }
-                else if (!writeKey(key, ent->lazystrlen(), "[ ]", cursor, maxSize, CurseSimpleOutput::getFlag(ent)) || (cursor.second - scrollTop > 0 && (cursor.second - scrollTop) > maxSize.second -1))
+                else if (!writeKey(key, ent->lazystrlen(), "[ ]", cursor, CurseSimpleOutput::getFlag(ent)))
+                    break;
+                if (hasReachedBottom(cursor.second, scrollTop, screenSize.second))
                     break;
             }
             else
             {
-                if (!writeKey(key, ent->lazystrlen(), cursor, maxSize, CurseSimpleOutput::getFlag(ent)))
+                if (!writeKey(key, ent->lazystrlen(), cursor, CurseSimpleOutput::getFlag(ent)))
                     break;
                 const JSonElement *saveSelection = selection;
                 if (selection == ent)
                     selection = **ent;
                 cursor.first += INDENT_LEVEL /2;
-                if (!redraw(cursor, maxSize, **ent))
+                if (!redraw(cursor, **ent))
                 {
                     selection = saveSelection;
                     cursor.first -= INDENT_LEVEL /2;
@@ -297,7 +301,7 @@ bool CurseSimpleOutput::writeContent(t_Cursor &cursor, const t_Cursor &maxSize,
         }
         else
         {
-            if (!redraw(cursor, maxSize, i))
+            if (!redraw(cursor, i))
                 break;
         }
         result = true;
@@ -307,7 +311,7 @@ bool CurseSimpleOutput::writeContent(t_Cursor &cursor, const t_Cursor &maxSize,
     return result;
 }
 
-bool CurseSimpleOutput::writeKey(const std::string &key, const size_t keylen, t_Cursor &cursor, const t_Cursor &maxSize, OutputFlag flags, unsigned int extraLen)
+bool CurseSimpleOutput::writeKey(const std::string &key, const size_t keylen, t_Cursor &cursor, OutputFlag flags, unsigned int extraLen)
 {
     if (cursor.second - scrollTop <= 0)
     {
@@ -316,14 +320,14 @@ bool CurseSimpleOutput::writeKey(const std::string &key, const size_t keylen, t_
     }
     char oldType = flags.type();
     flags.type(OutputFlag::TYPE_OBJKEY);
-    cursor.second += write(cursor.first, cursor.second, key, keylen, maxSize.first -extraLen -2, flags);
+    cursor.second += write(cursor.first, cursor.second, key, keylen, screenSize.first -extraLen -2, flags);
     flags.type(OutputFlag::TYPE_OBJ);
     write(": ", flags);
     flags.type(oldType);
-    return (cursor.second >= scrollTop || cursor.second <= maxSize.second +scrollTop);
+    return !hasReachedBottom(cursor.second, scrollTop, screenSize.second);
 }
 
-bool CurseSimpleOutput::writeKey(const std::string &key, const size_t keylen, const std::string &after, size_t afterlen, t_Cursor &cursor, const t_Cursor &maxSize, OutputFlag flags)
+bool CurseSimpleOutput::writeKey(const std::string &key, const size_t keylen, const std::string &after, size_t afterlen, t_Cursor &cursor, OutputFlag flags)
 {
     if (cursor.second - scrollTop <= 0)
     {
@@ -337,13 +341,13 @@ bool CurseSimpleOutput::writeKey(const std::string &key, const size_t keylen, co
     write(": ", flags);
     flags.type(oldType);
     write(after.c_str(), flags);
-    cursor.second += getNbLines(cursor.first +keylen +2 +afterlen, maxSize.first);
-    return (cursor.second >= scrollTop || (cursor.second - scrollTop) <= maxSize.second);
+    cursor.second += getNbLines(cursor.first +keylen +2 +afterlen, screenSize.first);
+    return !hasReachedBottom(cursor.second, scrollTop, screenSize.second);
 }
 
-bool CurseSimpleOutput::writeKey(const std::string &key, const size_t keylen, const std::string &after, t_Cursor &cursor, const t_Cursor &maxSize, OutputFlag flags)
+bool CurseSimpleOutput::writeKey(const std::string &key, const size_t keylen, const std::string &after, t_Cursor &cursor, OutputFlag flags)
 {
-    return writeKey(key, keylen, after, after.size(), cursor, maxSize, flags);
+    return writeKey(key, keylen, after, after.size(), cursor, flags);
 }
 
 unsigned int CurseSimpleOutput::write(const int &x, const int &y, const char item, unsigned int maxWidth, OutputFlag flags)
@@ -533,4 +537,8 @@ void CurseSimpleOutput::shutdown()
     screen = nullptr;
 }
 
+const t_Cursor CurseSimpleOutput::getScreenSize() const
+{
+    return getScreenSizeUnsafe();
+}
 

+ 68 - 43
src/curseSplitOutput.cpp

@@ -8,7 +8,7 @@
 #include <unistd.h>
 #include <signal.h>
 #include <curses.h>
-
+#include <alloca.h>
 #include "searchPattern.hh"
 #include "curseSplitOutput.hh"
 #include "jsonObject.hh"
@@ -42,10 +42,10 @@ CurseSplitOutput::~CurseSplitOutput()
 void CurseSplitOutput::run(const std::deque<std::string> &inputName, const std::deque<JSonElement*> &roots)
 {
     nbInputs = inputName.size();
-    const t_Cursor screenSize = getScreenSize();
     selectedWin = 0;
     destroyAllSubWin();
     subWindows.clear();
+    screenSize = getScreenSize(); // screenSize is based on nbInputs, we must refresh it
 
     for (size_t i =0; i < nbInputs; ++i)
     {
@@ -370,15 +370,15 @@ bool CurseSplitOutput::jumpToNextSearch()
     return true;
 }
 
-const Optional<bool> CurseSplitOutput::redrawOneItemToWorkingWin(t_subWindow &w, const t_Cursor &screenSize)
+const Optional<bool> CurseSplitOutput::redrawOneItemToWorkingWin(t_subWindow &w)
 {
     bool result;
 
     try {
         if (w.parentsIterators.empty())
-            result = redraw(w, screenSize, w.root);
+            result = redraw(w, w.root);
         else
-            result = redraw(w, screenSize, w.parentsIterators.top());
+            result = redraw(w, w.parentsIterators.top());
     }
     catch (SelectionOutOfRange &e)
     {
@@ -414,10 +414,25 @@ const Optional<bool> CurseSplitOutput::redrawOneItemToWorkingWin(t_subWindow &w,
     return Optional<bool>::of(false);
 }
 
+void CurseSplitOutput::onResizeHandler()
+{
+    size_t i =0;
+    clear();
+
+    for (t_subWindow &subwin: subWindows)
+    {
+        wresize(subwin.outerWin, screenSize.second +2, screenSize.first);
+        wresize(subwin.innerWin, screenSize.second, screenSize.first -2);
+        box(subwin.outerWin, 0, 0);
+        wrefresh(subwin.outerWin);
+        ++i;
+    }
+}
+
 bool CurseSplitOutput::redraw()
 {
-    const t_Cursor screenSize = getScreenSize();
     short writingDone = (1 << nbInputs) -1;
+    unsigned int *cursorInit = (unsigned int *)alloca(sizeof(*cursorInit) * nbInputs);
 
     workingWin = 0;
     for (t_subWindow &w : subWindows)
@@ -436,6 +451,8 @@ bool CurseSplitOutput::redraw()
     {
         // Display Gap (--)
         bool restart = false;
+        unsigned int maxLines = 0;
+
         workingWin = 0;
         for (t_subWindow &w : subWindows)
         {
@@ -447,7 +464,7 @@ bool CurseSplitOutput::redraw()
 
                 do
                 {
-                    const Optional<bool> wrote = redrawOneItemToWorkingWin(w, screenSize);
+                    const Optional<bool> wrote = redrawOneItemToWorkingWin(w);
 
                     if (wrote.absent())
                         return false;
@@ -478,24 +495,32 @@ bool CurseSplitOutput::redraw()
         workingWin = 0;
         for (t_subWindow &w : subWindows)
         {
+            cursorInit[workingWin] = w.cursor.second;
+
             if ((writingDone & (1 << workingWin)))
             {
-                const Optional<bool> wrote = redrawOneItemToWorkingWin(w, screenSize);
+                const Optional<bool> wrote = redrawOneItemToWorkingWin(w);
 
                 if (wrote.absent())
                     return false;
                 if (wrote.get())
                     writingDone &= ~(1 << workingWin);
+                maxLines = std::max(maxLines, w.cursor.second - cursorInit[workingWin]);
             }
             ++workingWin;
         }
+
+        // Display multi-lines gaps
+        workingWin = 0;
+        for (t_subWindow &w : subWindows)
+            w.cursor.second = cursorInit[workingWin++] + maxLines;
     }
     for (t_subWindow &w : subWindows)
         wrefresh(w.innerWin);
     return true;
 }
 
-bool CurseSplitOutput::writeContainer(const t_Cursor &maxSize, JSonContainer *item, bool opening)
+bool CurseSplitOutput::writeContainer(JSonContainer *item, bool opening)
 {
     char childDelimiter[2];
     t_subWindow &w = subWindows.at(workingWin);
@@ -508,27 +533,27 @@ bool CurseSplitOutput::writeContainer(const t_Cursor &maxSize, JSonContainer *it
     if (!opening) // Display close brackets
     {
         w.cursor.first -= INDENT_LEVEL;
-        w.cursor.second += write(w.cursor.first, w.cursor.second, childDelimiter[1], maxSize.first, CurseSplitOutput::getFlag(item));
+        w.cursor.second += write(w.cursor.first, w.cursor.second, childDelimiter[1], screenSize.first -2, CurseSplitOutput::getFlag(item));
     }
     else if (collapsed.find((const JSonContainer *)item) != collapsed.end()) // inline collapsed
     {
         std::string ss;
         ss.append(&childDelimiter[0], 1).append(" ... ").append(&childDelimiter[1], 1);
-        w.cursor.second += write(w.cursor.first, w.cursor.second, ss, 7, maxSize.first, CurseSplitOutput::getFlag(item));
+        w.cursor.second += write(w.cursor.first, w.cursor.second, ss, 7, screenSize.first -2, CurseSplitOutput::getFlag(item));
     }
     else // Display open brackets
     {
-        w.cursor.second += write(w.cursor.first, w.cursor.second, childDelimiter[0], maxSize.first, CurseSplitOutput::getFlag(item));
-        if (w.cursor.second > w.scrollTop && (w.cursor.second - w.scrollTop) > maxSize.second -1)
+        w.cursor.second += write(w.cursor.first, w.cursor.second, childDelimiter[0], screenSize.first -2, CurseSplitOutput::getFlag(item));
+        if (hasReachedBottom(w.cursor.second, w.scrollTop, screenSize.second))
             return false;
         w.parentsIterators.push(std::pair<int, JSonContainer *>(-1, item));
         w.cursor.first += INDENT_LEVEL;
         return true;
     }
-    return (w.cursor.second < w.scrollTop || (w.cursor.second - w.scrollTop) <= maxSize.second -1);
+    return !hasReachedBottom(w.cursor.second, w.scrollTop, screenSize.second);
 }
 
-bool CurseSplitOutput::writeKey(t_subWindow &w, const std::string &key, const size_t keylen, const t_Cursor &maxSize, OutputFlag flags, unsigned int extraLen)
+bool CurseSplitOutput::writeKey(t_subWindow &w, const std::string &key, const size_t keylen, OutputFlag flags, unsigned int extraLen)
 {
     if (w.cursor.second <= w.scrollTop)
     {
@@ -537,14 +562,14 @@ bool CurseSplitOutput::writeKey(t_subWindow &w, const std::string &key, const si
     }
     char oldType = flags.type();
     flags.type(OutputFlag::TYPE_OBJKEY);
-    w.cursor.second += write(w.cursor.first, w.cursor.second, key, keylen, maxSize.first -extraLen -2, flags);
+    w.cursor.second += write(w.cursor.first, w.cursor.second, key, keylen, screenSize.first -extraLen -2 -2, flags);
     flags.type(OutputFlag::TYPE_OBJ);
     write(": ", flags);
     flags.type(oldType);
-    return (w.cursor.second < w.scrollTop || (w.cursor.second - w.scrollTop) <= maxSize.second);
+    return !hasReachedBottom(w.cursor.second, w.scrollTop, screenSize.second);
 }
 
-bool CurseSplitOutput::writeKey(t_subWindow &w, const std::string &key, const size_t keylen, const std::string &after, const size_t afterlen, t_Cursor &cursor, const t_Cursor &maxWidth, OutputFlag flags)
+bool CurseSplitOutput::writeKey(t_subWindow &w, const std::string &key, const size_t keylen, const std::string &after, const size_t afterlen, t_Cursor &cursor, OutputFlag flags)
 {
     if (cursor.second <= w.scrollTop)
     {
@@ -558,13 +583,13 @@ bool CurseSplitOutput::writeKey(t_subWindow &w, const std::string &key, const si
     write(": ", flags);
     flags.type(oldType);
     write(after, flags);
-    cursor.second += getNbLines(cursor.first +keylen +2 +afterlen, maxWidth.first);
-    return (cursor.second < w.scrollTop || (cursor.second - w.scrollTop) <= maxWidth.second);
+    cursor.second += getNbLines(cursor.first +keylen +2 +afterlen, screenSize.first -2);
+    return !hasReachedBottom(w.cursor.second, w.scrollTop, screenSize.second);
 }
 
-bool CurseSplitOutput::writeKey(t_subWindow &w, const std::string &key, const size_t keylen, const std::string &after, t_Cursor &cursor, const t_Cursor &maxWidth, OutputFlag flags)
+bool CurseSplitOutput::writeKey(t_subWindow &w, const std::string &key, const size_t keylen, const std::string &after, t_Cursor &cursor, OutputFlag flags)
 {
-    return writeKey(w, key, keylen, after, after.length(), cursor, maxWidth, flags);
+    return writeKey(w, key, keylen, after, after.length(), cursor, flags);
 }
 
 bool CurseSplitOutput::isAdded(const JSonElement *e) const
@@ -583,7 +608,7 @@ bool CurseSplitOutput::isAdded(const std::pair<int, JSonContainer *> &item) cons
     return isAdded(e);
 }
 
-bool CurseSplitOutput::redraw(t_subWindow &w, const t_Cursor &maxSize, std::pair<int, JSonContainer *> &item)
+bool CurseSplitOutput::redraw(t_subWindow &w, std::pair<int, JSonContainer *> &item)
 {
     JSonElement *currentItem;
 
@@ -591,34 +616,34 @@ bool CurseSplitOutput::redraw(t_subWindow &w, const t_Cursor &maxSize, std::pair
     if ((unsigned int) item.first == item.second->size())
     {
         w.parentsIterators.pop();
-        return writeContainer(maxSize, item.second, false);
+        return writeContainer(item.second, false);
     }
     currentItem = list_at<JSonElement*>(*(item.second), item.first);
-    return redraw(w, maxSize, currentItem);
+    return redraw(w, currentItem);
 }
 
-bool CurseSplitOutput::redraw(t_subWindow &w, const t_Cursor &maxSize, JSonElement *item)
+bool CurseSplitOutput::redraw(t_subWindow &w, JSonElement *item)
 {
     checkSelection(item);
     if (dynamic_cast<const JSonContainer*>(item))
     {
-        if (!writeContainer(maxSize, (JSonContainer *) item))
+        if (!writeContainer((JSonContainer *) item))
             return false;
     }
     else if (dynamic_cast<JSonObjectEntry*>(item))
     {
-        return writeObjectEntry(w, maxSize, (JSonObjectEntry*) item);
+        return writeObjectEntry(w, (JSonObjectEntry*) item);
     }
     else
     {
-        w.cursor.second += CurseOutput::write(w.cursor.first, w.cursor.second, item, maxSize.first, CurseSplitOutput::getFlag(item));
-        if (w.cursor.second > w.scrollTop && (w.cursor.second - w.scrollTop) > maxSize.second -1)
+        w.cursor.second += CurseOutput::write(w.cursor.first, w.cursor.second, item, screenSize.first -2, CurseSplitOutput::getFlag(item));
+        if (hasReachedBottom(w.cursor.second, w.scrollTop, screenSize.second))
             return false;
     }
     return true;
 }
 
-bool CurseSplitOutput::writeObjectEntry(t_subWindow &w, const t_Cursor &maxSize, JSonObjectEntry *ent)
+bool CurseSplitOutput::writeObjectEntry(t_subWindow &w, JSonObjectEntry *ent)
 {
     bool isContainer = (dynamic_cast<JSonContainer *>(**ent) != nullptr);
     std::string key = ent->stringify();
@@ -627,38 +652,39 @@ bool CurseSplitOutput::writeObjectEntry(t_subWindow &w, const t_Cursor &maxSize,
     {
         if (dynamic_cast<JSonObject *>(**ent))
         {
-            if (!writeKey(w, key, ent->lazystrlen(), "{ ... }", w.cursor, maxSize, getFlag(ent)) || (w.cursor.second > w.scrollTop && (w.cursor.second - w.scrollTop) > maxSize.second -1))
+            if (!writeKey(w, key, ent->lazystrlen(), "{ ... }", w.cursor, getFlag(ent)))
                 return false;
         }
-        else if (!writeKey(w, key, ent->lazystrlen(), "[ ... ]", w.cursor, maxSize, getFlag(ent)) || (w.cursor.second > w.scrollTop && (w.cursor.second - w.scrollTop) > maxSize.second -1))
+        else if (!writeKey(w, key, ent->lazystrlen(), "[ ... ]", w.cursor, getFlag(ent)))
+            return false;
+        if (hasReachedBottom(w.cursor.second, w.scrollTop, screenSize.second))
             return false;
     }
     else if (!isContainer) // inline value
     {
         JSonElement *eContent = **ent;
-        if (!writeKey(w, key, ent->lazystrlen(), eContent->stringify(), eContent->lazystrlen(), w.cursor, maxSize, getFlag(ent))
-                || (w.cursor.second > w.scrollTop && (w.cursor.second - w.scrollTop) > maxSize.second -1))
+        if (!writeKey(w, key, ent->lazystrlen(), eContent->stringify(), eContent->lazystrlen(), w.cursor, getFlag(ent)))
             return false;
     }
     else if (((JSonContainer*)(**ent))->size() == 0) // inline empty
     {
         if (dynamic_cast<const JSonObject *>(**ent) )
         {
-            if (!writeKey(w, key, ent->lazystrlen(), "{ }", w.cursor, maxSize, getFlag(ent)) || (w.cursor.second > w.scrollTop && (w.cursor.second - w.scrollTop) > maxSize.second -1))
+            if (!writeKey(w, key, ent->lazystrlen(), "{ }", w.cursor, getFlag(ent)))
                 return false;
         }
-        else if (!writeKey(w, key, ent->lazystrlen(), "[ ]", w.cursor, maxSize, getFlag(ent)) || (w.cursor.second > w.scrollTop && (w.cursor.second - w.scrollTop) > maxSize.second -1))
+        else if (!writeKey(w, key, ent->lazystrlen(), "[ ]", w.cursor, getFlag(ent)))
+            return false;
+        if (hasReachedBottom(w.cursor.second, w.scrollTop, screenSize.second))
             return false;
     }
     else // Container
     {
-        if (!writeKey(w, key, ent->lazystrlen(), maxSize, getFlag(ent)))
+        if (!writeKey(w, key, ent->lazystrlen(), getFlag(ent)))
             return false;
-        writeContainer(maxSize, (JSonContainer*)(**ent), true);
+        writeContainer((JSonContainer*)(**ent), true);
     }
-    if (w.cursor.second > w.scrollTop && (w.cursor.second - w.scrollTop) > maxSize.second -1)
-        return false;
-    return true;
+    return !hasReachedBottom(w.cursor.second, w.scrollTop, screenSize.second);
 }
 
 unsigned int CurseSplitOutput::write(const int &x, const int &y, const char item, unsigned int maxWidth, OutputFlag flags)
@@ -776,7 +802,6 @@ void CurseSplitOutput::destroyAllSubWin()
 
 void CurseSplitOutput::writeTopLine(const std::string &buffer, short color) const
 {
-    const t_Cursor screenSize = getScreenSize();
     const size_t bufsize = buffer.size();
     WINDOW *currentWin = subWindows.at(workingWin).innerWin;
 

+ 1 - 1
src/main.cpp

@@ -16,7 +16,7 @@ void displayException(const std::string &filename, const Params &params, const s
 {
     const std::string buffer = e.getHistory();
 
-    std::cerr << params.getProgName() << ": " << filename << " [" << type << "] at line " << e.currentLine() << ", " << e.currentCol() << " ("  << e.what() << ") while reading" << std::endl;
+    std::cerr << params.getProgName() << ": " << filename << " [" << type << "] at line " << e.currentLine() << ", col " << e.currentCol() << " ("  << e.what() << ") while reading" << std::endl;
     std::cerr << buffer << std::endl << std::string(buffer.size() -1, '~') << '^' << std::endl;
 }
 

+ 29 - 11
src/streamConsumer.cpp

@@ -208,32 +208,43 @@ bool StreamConsumer::consumeEscapedChar(char c, std::stringstream &buf)
 JSonElement *StreamConsumer::consumeBool(JSonContainer *parent, std::stringstream &buf, char firstChar)
 {
     size_t read =1;
+    const char firstLowerChar = std::tolower(firstChar);
+    std::string rawInput;
 
     buf.str("");
     buf.clear();
-    buf.write(&firstChar, 1);
+    buf.write(&firstLowerChar, 1);
+    rawInput += firstChar;
 
     //TODO batch-get 3 char, then do that
     while (stream.good())
     {
-        char c = stream.get();
+        const char c = stream.get();
+        const char cLower = std::tolower(c);
         history.put(c);
 
-        if (c == 'a' || c == 'e' || c == 'l' || c == 'r' || c == 's' || c == 'u')
+        if (cLower == 'a' || cLower == 'e' || cLower == 'l' || cLower == 'r' || cLower == 's' || cLower == 'u')
         {
-            if ((read >= 5 && firstChar == 'f') || (read >= 4 && firstChar == 't'))
+            if ((read >= 5 && firstLowerChar == 'f') || (read >= 4 && firstLowerChar == 't'))
                 throw JsonFormatException(stream.tellg(), history);
-            buf.write(&c, 1);
+            buf.write(&cLower, 1);
             read++;
+            rawInput += c;
         }
+        else if ((buf.str() != "true" && buf.str() != "false") || (buf.str() != rawInput && params->isStrict()))
+            throw JsonFormatException(stream.tellg(), history);
         else if (buf.str() == "true")
         {
+            if (buf.str() != rawInput)
+                warnings.push_back(Warning(JsonFormatException(stream.tellg(), history)));
             history.pop_back();
             stream.unget();
             return new JSonPrimitive<bool>(parent, true);
         }
         else if (buf.str() == "false")
         {
+            if (buf.str() != rawInput)
+                warnings.push_back(Warning(JsonFormatException(stream.tellg(), history)));
             history.pop_back();
             stream.unget();
             return new JSonPrimitive<bool>(parent, false);
@@ -296,9 +307,10 @@ JSonElement *StreamConsumer::consumeNumber(JSonContainer *parent, std::stringstr
     return nullptr;
 }
 
-JSonElement *StreamConsumer::consumeNull(JSonContainer *parent, std::stringstream &buf)
+JSonElement *StreamConsumer::consumeNull(JSonContainer *parent, std::stringstream &buf, char firstChar)
 {
-    char _buf[5] = { 'n', '\0', '\0', '\0', '\0' };
+    char _buf[5] = { firstChar, '\0', '\0', '\0', '\0' };
+    std::string _bufLower = "n";
 
     buf.str("");
     buf.clear();
@@ -312,8 +324,14 @@ JSonElement *StreamConsumer::consumeNull(JSonContainer *parent, std::stringstrea
         buf.clear();
         return nullptr;
     }
-    if (std::string("null") == _buf)
+    for (int i =1; i < 4; ++i)
+        _bufLower += std::tolower(_buf[i]);
+    if (_bufLower == "null" && (_bufLower == buf.str() || !params->isStrict()))
+    {
+        if (buf.str() != "null")
+            warnings.push_back(Warning(JsonFormatException(stream.tellg(), history)));
         return new JSonPrimitive<Null>(parent, Null());
+    }
     throw JsonFormatException(stream.tellg(), history);
 }
 
@@ -327,10 +345,10 @@ JSonElement *StreamConsumer::consumeToken(JSonContainer *parent, std::stringstre
         //!InString, !inbool
         if (c == '"')
             return consumeString(parent, buf);
-        else if (c == 't' || c == 'f')
+        else if (c == 't' || c == 'f' || c == 'T' || c == 'F')
             return consumeBool(parent, buf, c);
-        else if (c == 'n')
-            return consumeNull(parent, buf);
+        else if (c == 'n' || c == 'N')
+            return consumeNull(parent, buf, c);
         else if ((c >= '0' && c <= '9') || c == '.' || c == '-')
             return consumeNumber(parent, buf, c);
         else if (c == '{' || c == '[' || c == '}' || c == ']' || c == ':' || c == ',')