Explorar el Código

[add][Refs #9] doc
[refactor] removed useless getbegyx()
[refactor] removed useless selectIsFirst (scrolling toward top is now step-by-step)
[refactor] JsonHexvalueException should be a JsonFormatException
[refactor] primitive now contains its stringified value
[refactor] rewritten hexstring to int with templates
[refactor] moved typeinfo to Warning
[refactor] removed useless parent from checkSelection
[refactor] renamed topleft to scrollTop (atm we don't want to scroll left-right any more)
[refactor] optimized search buffer
[quickfix] check new-line in LinearBuffer
[refactor] Warning now have a copy of exception

isundil hace 9 años
padre
commit
81206615b9

+ 7 - 0
include/config.h

@@ -4,10 +4,17 @@
  * Author: isundil <isundill@gmail.com>
 **/
 
+/**
+ * Max history to keep in error messages
+**/
 #ifndef  ERROR_HISTORY_LEN
 # define ERROR_HISTORY_LEN 45
 #endif //ERROR_HISTORY_LEN
 
+/**
+ * Indent increment (in spaces)
+**/
 #ifndef  INDENT_LEVEL
 # define INDENT_LEVEL 4
 #endif //INDENT_LEVEL
+

+ 104 - 11
include/curseOutput.hh

@@ -26,27 +26,73 @@ class CurseOutput
         CurseOutput(JSonElement *rootData, const Params &);
         virtual ~CurseOutput();
 
+        /**
+         * Display data, and shutdown ncurses at the end
+        **/
         void run();
+        /**
+         * Called on SIG* while displaying data
+         * Do not use (private).
+        **/
         bool onsig(int signo);
 
     private:
+        /**
+         * until kill-input, display data and read user inputs
+        **/
         virtual void loop();
 
     protected:
+        /**
+         * Initialize ncurses
+        **/
         void init();
+        /**
+         * Release ncurses
+        **/
         void shutdown();
         /**
          * return false if bottom of screen is touched
+         * redraw all data
         **/
         bool redraw();
+        /**
+         * Like redraw, but append a message on the last line
+        **/
         bool redraw(const std::string &errorMsg);
-        bool redraw(std::pair<int, int> &, const std::pair<unsigned int, unsigned int> &maxWidth, const JSonElement *, const JSonContainer *);
+        /**
+         * redraw item and children
+        **/
+        bool redraw(std::pair<int, int> &, const std::pair<unsigned int, unsigned int> &maxWidth, const JSonElement *item);
+        /**
+         * Wait for input
+         * @return false if ncurses should stop
+        **/
         bool readInput();
-        void getScreenSize(std::pair<unsigned int, unsigned int> &) const;
-        void getScreenSize(std::pair<unsigned int, unsigned int> &, std::pair<int, int> &) const;
-        void checkSelection(const JSonElement *item, const JSonElement *parent, const std::pair<int, int>&);
+        /**
+         * get the screen size
+        **/
+        const std::pair<unsigned int, unsigned int> getScreenSize() const;
+        /**
+         * set the select_up and select_down pointers, scroll to selection if it is above view port
+        **/
+        void checkSelection(const JSonElement *item, const std::pair<int, int>&);
+        /**
+         * Return the number of lines written while writting nbChar bytes
+         * @param nbChar col written
+         * @param @maxWidth screen width
+         * @return the number of line written
+        **/
         static unsigned int getNbLines(float nbChar, unsigned int maxWidth);
+        /**
+         * get flags to be passed to write.
+         * Contains indications on who to write item
+        **/
         const OutputFlag getFlag(const JSonElement *item) const;
+
+        /**
+         * Write data
+        **/
         void write(const std::string &str, unsigned int maxWidth, const OutputFlag flags) const;
         unsigned int write(const int &x, const int &y, const JSonElement *item, unsigned int maxWidth, const OutputFlag);
         unsigned int write(const int &x, const int &y, const std::string &item, unsigned int maxWidth, const OutputFlag);
@@ -56,8 +102,19 @@ class CurseOutput
         bool writeContainer(std::pair<int, int> &, const std::pair<unsigned int, unsigned int> &maxSize, const JSonContainer *);
         bool writeContent(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, const std::list<JSonElement *> * obj);
 
+        /**
+         * find next search occurence and select it (wich cause viewport to move, eventually)
+         * Have it own redraw because may have to write message
+        **/
         bool jumpToNextSearch(bool scanParent, bool redraw, const JSonElement *initial_selection);
+        /**
+         * prompt for user input, and return it
+         * @throws noInputException if user use a kill-key (to exit buffer)
+        **/
         const std::string search();
+        /**
+         * Write a message on the last line, using color
+        **/
         void writeBottomLine(const std::string &currentBuffer, short color) const;
 
         /**
@@ -65,18 +122,54 @@ class CurseOutput
         **/
         void unfold(const JSonElement *);
 
+
+        // Fields
+        /**
+         * collapsed items
+        **/
         std::set<const JSonContainer *> collapsed;
 
-        const JSonElement *data, *selection;
-        const Params &params;
+        /**
+         * Root item
+        **/
+        const JSonElement *data;
+        /**
+         * selected item
+        **/
+        const JSonElement *selection;
+        /**
+         * currently searching pattern
+        **/
         std::string search_pattern;
+        /**
+         * prev/next items to be selected on up/down keys
+        **/
+        const JSonElement *select_up, *select_down;
+        /**
+         * Program params (ac/av)
+        **/
+        const Params &params;
+        /**
+         * ncurses stuff
+        **/
         SCREEN *screen;
         FILE *screen_fd;
+        /**
+         * Used by signals to stop reading input and shutdown ncurses
+        **/
         bool breakLoop;
-        int topleft;
-        std::set<char> colors;
-
-        const JSonElement *select_up, *select_down;
-        bool selectFound, selectIsLast, selectIsFirst;
+        /**
+         * Viewport start
+        **/
+        int scrollTop;
+        /**
+         * initialized colors
+        **/
+        std::set<char /* OutputFlag::TYPE_SOMETHING */> colors;
+        /**
+         * Selection helpers
+         * Used for moving viewport
+        **/
+        bool selectFound, selectIsLast;
 };
 

+ 4 - 0
include/jsonContainer.hh

@@ -14,6 +14,10 @@ class JSonContainer: public JSonElement, public std::list<JSonElement*>
     public:
         JSonContainer(JSonContainer *parent);
         virtual ~JSonContainer();
+
+        /**
+         * Get the first item of this container
+        **/
         virtual JSonElement *firstChild() =0;
         virtual const JSonElement *firstChild() const =0;
 };

+ 25 - 0
include/jsonElement.hh

@@ -16,19 +16,44 @@ class JSonElement
         JSonElement(JSonElement *parent);
         virtual ~JSonElement();
 
+        /**
+         * return string-representative of this JSonElement
+        **/
         virtual std::string stringify() const =0;
+        /**
+         * return number of parents this item has
+        **/
         unsigned int getLevel() const;
+
+        /**
+         * Get the parent element
+        **/
         JSonElement *getParent();
         const JSonElement *getParent() const;
 
+        /**
+         * set parent.
+         * Used for lazy-init
+        **/
         void setParent(JSonElement *parent);
 
+        /**
+         * return previous child
+        **/
         const JSonElement *findPrev() const;
         const JSonElement *findNext() const;
+
+        /**
+         * check if this element match SearchQuery
+        **/
         virtual bool match(const std::string &) const;
 
     private:
         JSonElement();
+        /**
+         * parent container
+         * Not a JSonContainer because JSonObjectEntry can be a parent and isn't a JSonContainer either
+        **/
         JSonElement *parent;
 };
 

+ 32 - 10
include/jsonException.hh

@@ -10,9 +10,15 @@
 #include "config.h"
 #include "linearHistory.hh"
 
+/**
+ * Reach end of input prematurelly
+**/
 class EofException: public std::exception
 { };
 
+/**
+ * std json parse exception
+**/
 class JsonException: public std::exception
 {
     public:
@@ -26,36 +32,52 @@ class JsonException: public std::exception
     protected:
         const unsigned long long offset;
         const LinearHistory history;
-        const std::string _what;
-};
-
-class JsonHexvalueException: public JsonException
-{
-    public:
-        JsonHexvalueException(const std::string &what, unsigned long long offset, LinearHistory &hist);
-        JsonHexvalueException(const char what, unsigned long long offset, LinearHistory &hist);
-
-        static std::string msg(char c);
+        std::string _what;
 };
 
+/**
+ * Expected JSon value (primitive / object / array), got crap
+**/
 class JsonNotJsonException: public JsonException
 {
     public:
         JsonNotJsonException(unsigned long long offet, LinearHistory &h);
 };
 
+/**
+ * Expected char, got crap
+**/
 class JsonUnexpectedException: public JsonException
 {
     public:
         JsonUnexpectedException(const char expected, unsigned long long offset, LinearHistory &h);
 };
 
+/**
+ * cannot interpret input as boolean/number
+**/
 class JsonFormatException: public JsonException
 {
     public:
         JsonFormatException(unsigned long long offset, LinearHistory &h);
 };
 
+/**
+ * Invalid hexadecimal value
+**/
+class JsonHexvalueException: public JsonFormatException
+{
+    public:
+        JsonHexvalueException(const std::string &what, unsigned long long offset, LinearHistory &hist);
+        JsonHexvalueException(const char what, unsigned long long offset, LinearHistory &hist);
+
+        static std::string msg(char c);
+};
+
+/**
+ * unknown escaped entry in string
+ * (eg. \crap)
+**/
 class JsonEscapedException: public JsonException
 {
     public:

+ 24 - 2
include/jsonObject.hh

@@ -17,24 +17,46 @@ class JSonObject: public JSonContainer
         JSonObject(JSonContainer *parent);
         virtual ~JSonObject();
 
+        /**
+         * Add entry
+        **/
         void push(const std::string &key, JSonElement *child);
+
+        /**
+         * find object by key
+        **/
         JSonObject::const_iterator find(const std::string &key) const;
+        /**
+         * remove object by key
+        **/
         bool erase(const std::string &);
+        /**
+         * check if object exists
+        **/
         bool contains(const std::string &) const;
 
+        /**
+         * fetch object by key
+        **/
+        const JSonElement* get(const std::string &) const;
+
         virtual JSonElement *firstChild();
         virtual const JSonElement *firstChild() const;
 
-        const JSonElement* get(const std::string &) const;
-
         virtual std::string stringify() const;
 
+    /**
+     * multiple objects exists for this key
+    **/
     class DoubleKeyException: public JsonException
     {
         public:
             DoubleKeyException(unsigned long long offset, const std::string &key, LinearHistory &buf);
     };
 
+    /**
+     * Invalid value for key
+    **/
     class NotAKeyException: public JsonException
     {
         public:

+ 7 - 0
include/jsonObjectEntry.hh

@@ -19,8 +19,15 @@ class JSonObjectEntry: public JSonElement
         std::string stringify() const;
 
         bool operator==(const std::string &) const;
+        /**
+         * Get associated value
+        **/
         const JSonElement *operator*() const;
         JSonElement *operator*();
+
+        /**
+         * check if key or value match search pattern
+        **/
         bool match(const std::string &) const;
 
     protected:

+ 27 - 11
include/jsonPrimitive.hh

@@ -21,35 +21,51 @@ class JSonPrimitive: public JSonElement, public AJSonPrimitive
         JSonPrimitive(JSonContainer *parent, T const &v);
         virtual ~JSonPrimitive();
 
+        /**
+         * get value as raw type
+        **/
         T getValue() const;
-        virtual std::string stringify() const;
+        /**
+         * get stringified value
+        **/
+        std::string stringify() const;
 
         bool operator<(const JSonPrimitive<T> &other) const;
         bool operator==(const JSonPrimitive<T> &other) const;
 
     protected:
+        /**
+         * convert raw type to string
+        **/
+        virtual std::string toString() const;
+
+        /**
+         * raw value
+        **/
         const T value;
+        /**
+         * stringified value
+        **/
+        const std::string stringValue;
 };
 
 template<typename T>
-JSonPrimitive<T>::JSonPrimitive(JSonContainer *parent, T const &v): JSonElement(parent), value(v)
+JSonPrimitive<T>::JSonPrimitive(JSonContainer *parent, T const &v): JSonElement(parent), value(v), stringValue(toString())
 { }
 
 template<typename T>
 T JSonPrimitive<T>::getValue() const
-{
-    return value;
-}
+{ return value; }
+
+template<typename T>
+std::string JSonPrimitive<T>::stringify() const
+{ return stringValue; }
 
 template<typename T>
 bool JSonPrimitive<T>::operator<(const JSonPrimitive<T> &other) const
-{
-    return value < other.value;
-}
+{ return value < other.value; }
 
 template<typename T>
 bool JSonPrimitive<T>::operator==(const JSonPrimitive<T> &other) const
-{
-    return value == other.value;
-}
+{ return value == other.value; }
 

+ 13 - 0
include/linearHistory.hh

@@ -15,13 +15,26 @@ class LinearHistory: public WrappedBuffer<char, ERROR_HISTORY_LEN>
         LinearHistory();
         ~LinearHistory();
 
+        /**
+         * Get line number
+        **/
         unsigned int currentLine() const;
 
+        /**
+         * Insert char(s)
+         * If new-line found, reinitialize and increment line
+        **/
         void put(char item);
         void put(char item[], unsigned int count);
 
     private:
+        /**
+         * True if new line found, and should reset at new put
+        **/
         bool willReset;
+        /**
+         * Current line
+        **/
         unsigned int line;
 };
 

+ 12 - 0
include/outputFlag.hh

@@ -12,14 +12,26 @@ class OutputFlag
         OutputFlag(short mode =0);
         virtual ~OutputFlag();
 
+        /**
+         * get/set SELECTED byte
+        **/
         bool selected() const;
         bool selected(bool v);
 
+        /**
+         * get/set item's type
+        **/
         char type() const;
         char type(char t);
 
     protected:
+        /**
+         * item mode bitmask
+        **/
         short mode;
+        /**
+         * item type
+        **/
         char _type;
 
     public:

+ 36 - 3
include/params.hh

@@ -13,8 +13,18 @@
 class AParams
 {
     public:
+        /**
+         * true if --ascii
+        **/
         virtual bool isIgnoringUnicode() const =0;
+        /**
+         * false if -W
+        **/
         virtual bool isStrict() const =0;
+        /**
+         * true if --color match conditions
+        **/
+        virtual bool colorEnabled() const =0;
 };
 
 class Params: public AParams
@@ -23,20 +33,43 @@ class Params: public AParams
         Params(int ac, char **av);
         virtual ~Params();
 
+        /**
+         * retun input
+         * can be file stream (-f), stringstream ( -- INPUT), or std::cin (none)
+        **/
         std::basic_istream<char> &getInput() const;
+        /**
+         * false if invalid argument is passed
+        **/
         bool isValid() const;
-        bool isStrict() const;
-        bool colorEnabled() const;
 
+        /**
+         * print usage
+         * @param program name
+        **/
         static void usage(const std::string &) noexcept;
-
+        /**
+         * get argv[0]
+        **/
         const std::string &getProgName() const;
+
+        /**
+         * flags
+        **/
+        bool isStrict() const;
+        bool colorEnabled() const;
         bool isIgnoringUnicode() const;
 
     private:
+        /**
+         * input stream
+         * can be null for stdin
+        **/
         std::basic_istream<char> *input;
+
         const std::string progName;
         std::list<std::string> params;
+
         bool ignoreUnicode;
         bool colorMode;
         bool strict;

+ 51 - 6
include/streamConsumer.hh

@@ -17,36 +17,81 @@
 class StreamConsumer
 {
     public:
+        /**
+         * constructor
+         * does not read yet
+        **/
         StreamConsumer(std::istream &stream);
         virtual ~StreamConsumer();
 
+        /**
+         * read from stream and set root data
+         * @return current instance
+        **/
         StreamConsumer *read();
-        JSonElement * const getRoot() const;
+        /**
+         * get root node
+        **/
+        const JSonElement * const getRoot() const;
+        JSonElement * const getRoot();
+
+        /**
+         * return non-blocking error messages
+        **/
         const std::list<Warning> &getMessages() const;
 
+        /**
+         * set builder's params
+        **/
         StreamConsumer *withConfig(const AParams *);
 
     private:
         /**
-         * @return true on success
+         * @return non-null on successfully read JSonElement, or null if token (',', '[', ...)
         **/
         JSonElement *consumeToken(JSonContainer *parent, std::string &buf);
+        /**
+         * read next item, fill object or array if found
+        **/
         JSonElement *readNext(JSonContainer *parent);
 
+        /**
+         * fill object
+        **/
         JSonObject *readObject(JSonContainer *parent);
+        /**
+         * fill array
+        **/
         JSonArray *readArray(JSonContainer *parent);
+        /**
+         * out of token, should we ignore that char ?
+        **/
         bool ignoreChar(char c) const noexcept;
+        /**
+         * compute unicode value and append it to buffer
+        **/
         static void appendUnicode(const char [4], std::string &);
 
+        /**
+         * input stream
+        **/
         std::istream &stream;
+        /**
+         * once read, contains root element
+        **/
         JSonElement *root;
+        /**
+         * builder params (program's one in fact)
+        **/
         const AParams *params;
 
+        /**
+         * non-blocking errors
+        **/
         std::list<Warning> warnings;
+        /**
+         * last read input
+        **/
         LinearHistory history;
-
-    private:
-        static float _stof(const std::string &);
-        static float _stof(const char *);
 };
 

+ 15 - 3
include/warning.hh

@@ -11,13 +11,25 @@
 class Warning
 {
     public:
-        Warning(const JsonException *);
+        Warning(const JsonException &);
         ~Warning();
 
+        /**
+         * get exception representing non-blocking error
+        **/
         const JsonException &operator()() const;
-        const JsonException *getPtrUnsafe() const;
+        /**
+         * Because of copy, we can't get warning typeinfo
+        **/
+        const std::string &getType() const;
+
+        /**
+         * return type of given exception
+        **/
+        static std::string getType(const std::exception &);
 
     private:
-        const JsonException *what;
+        JsonException what;
+        std::string type;
 };
 

+ 22 - 2
include/wrappedBuffer.hpp

@@ -6,9 +6,16 @@
 
 #pragma once
 
+#include <stdexcept>
 #include <string.h>
 #include <string>
 
+class NotImplementedException: public std::logic_error
+{
+    public:
+        NotImplementedException(): std::logic_error("Not implemented") {};
+};
+
 template <typename T, int SIZE =10>
 class WrappedBuffer
 {
@@ -16,19 +23,31 @@ class WrappedBuffer
         WrappedBuffer();
         virtual ~WrappedBuffer();
 
+        /**
+         * append item(s) to buffer
+        **/
         virtual void put(T item);
-        virtual void put(T item[], unsigned int count);
+        virtual void put(T items[], unsigned int count);
+        /**
+         * remove last item from buffer
+        **/
         void pop_back();
+        /**
+         * empty the buffer
+        **/
         void reset();
 
         /**
          * @return total size appended since instanciation or clear()
         **/
         unsigned int totalSize() const;
+        /**
+         * @return Current size (cannot be greater than SIZE
+        **/
         unsigned int size() const;
 
         /**
-         * @return Current size (cannot be greater than SIZE
+         * @return basic_string representation of the buffer
         **/
         std::basic_string<T> toString() const;
         T* toArray(T arr[SIZE]) const;
@@ -175,6 +194,7 @@ std::basic_string<T> WrappedBuffer<T, SIZE>::toString() const
 template<typename T, int SIZE>
 T* WrappedBuffer<T, SIZE>::toArray(T arr[SIZE]) const
 {
+    throw NotImplementedException();
     if (!arr)
         arr = new T[SIZE]();
     //TODO

+ 36 - 48
src/curseOutput.cpp

@@ -78,17 +78,15 @@ static void _resizeFnc(int signo)
 
 bool CurseOutput::redraw()
 {
-    std::pair<unsigned int, unsigned int> screenSize;
-    std::pair<int, int> cursor;
+    const std::pair<unsigned int, unsigned int> screenSize = getScreenSize();
+    std::pair<int, int> cursor(0, 0);
     bool result;
 
     select_up = select_down = nullptr;
-    selectFound = selectIsLast = selectIsFirst = false;
-    getScreenSize(screenSize, cursor);
-    cursor.first = cursor.second = 0;
+    selectFound = selectIsLast = false;
     clear();
     try {
-        result = redraw(cursor, screenSize, data, dynamic_cast<const JSonContainer *> (data));
+        result = redraw(cursor, screenSize, data);
     }
     catch (SelectionOutOfRange &e)
     {
@@ -96,7 +94,7 @@ bool CurseOutput::redraw()
     }
     if (!result && !selectFound)
     {
-        topleft++;
+        scrollTop++;
         return false;
     }
     if (!result && !select_down)
@@ -125,9 +123,9 @@ bool CurseOutput::redraw(const std::string &errorMsg)
     return result;
 }
 
-bool CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, const JSonElement *item, const JSonContainer *parent)
+bool CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, const JSonElement *item)
 {
-    checkSelection(item, parent, cursor);
+    checkSelection(item, cursor);
     if (dynamic_cast<const JSonContainer*>(item))
     {
         if (!writeContainer(cursor, maxSize, (const JSonContainer *) item))
@@ -136,7 +134,7 @@ bool CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<unsigned i
     else
     {
         cursor.second += write(cursor.first, cursor.second, item, maxSize.first, getFlag(item));
-        if (cursor.second - topleft > 0 && (unsigned)(cursor.second - topleft) > maxSize.second -1)
+        if (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1)
             return false;
     }
     return true;
@@ -160,13 +158,13 @@ bool CurseOutput::writeContainer(std::pair<int, int> &cursor, const std::pair<un
     else
     {
         cursor.second += write(cursor.first, cursor.second, childDelimiter[0], maxSize.first, getFlag(item));
-        if (cursor.second - topleft > 0 && (unsigned)(cursor.second - topleft) > maxSize.second -1)
+        if (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1)
                 return false;
         if (!writeContent(cursor, maxSize, (const std::list<JSonElement *> *)item))
             return false;
         cursor.second += write(cursor.first, cursor.second, childDelimiter[1], maxSize.first, getFlag(item));
     }
-    return (cursor.second - topleft < 0 || (unsigned)(cursor.second - topleft) <= maxSize.second -1);
+    return (cursor.second - scrollTop < 0 || (unsigned)(cursor.second - scrollTop) <= maxSize.second -1);
 }
 
 bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, const std::list<JSonElement*> *_item)
@@ -184,7 +182,7 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
             JSonObjectEntry *ent = (JSonObjectEntry*) i;
             bool isContainer = (dynamic_cast<const JSonContainer *>(**ent) != nullptr);
             std::string key = ent->stringify();
-            checkSelection(ent, (JSonContainer*) item, cursor);
+            checkSelection(ent, cursor);
             if (isContainer && collapsed.find((const JSonContainer*)(**ent)) != collapsed.cend())
             {
                 if (dynamic_cast<const JSonObject *>(**ent))
@@ -192,12 +190,12 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
                     if (!writeKey(key, "{ ... }", cursor, maxSize, getFlag(ent)))
                         break;
                 }
-                else if (!writeKey(key, "[ ... ]", cursor, maxSize, getFlag(ent)) || (cursor.second - topleft > 0 && (unsigned)(cursor.second - topleft) > maxSize.second -1))
+                else if (!writeKey(key, "[ ... ]", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                     break;
             }
             else if (!isContainer)
             {
-                if (!writeKey(key, ((**ent)->stringify()), cursor, maxSize, getFlag(ent)) || (cursor.second - topleft > 0 && (unsigned)(cursor.second - topleft) > maxSize.second -1))
+                if (!writeKey(key, ((**ent)->stringify()), cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                     break;
             }
             else if (((JSonContainer*)(**ent))->size() == 0)
@@ -207,7 +205,7 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
                     if (!writeKey(key, "{ }", cursor, maxSize, getFlag(ent)))
                         break;
                 }
-                else if (!writeKey(key, "[ ]", cursor, maxSize, getFlag(ent)) || (cursor.second - topleft > 0 && (unsigned)(cursor.second - topleft) > maxSize.second -1))
+                else if (!writeKey(key, "[ ]", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                     break;
             }
             else
@@ -218,7 +216,7 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
                 if (selection == ent)
                     selection = **ent;
                 cursor.first += INDENT_LEVEL /2;
-                if (!redraw(cursor, maxSize, **ent, (const JSonContainer *)item))
+                if (!redraw(cursor, maxSize, **ent))
                 {
                     selection = saveSelection;
                     cursor.first -= INDENT_LEVEL /2;
@@ -230,7 +228,7 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
         }
         else
         {
-            if (!redraw(cursor, maxSize, i, (const JSonContainer *)item))
+            if (!redraw(cursor, maxSize, i))
                 break;
         }
         result = true;
@@ -242,7 +240,7 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
 
 bool CurseOutput::writeKey(const std::string &key, const std::string &after, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags)
 {
-    if (cursor.second - topleft < 0)
+    if (cursor.second - scrollTop < 0)
     {
         cursor.second++;
         return true;
@@ -256,7 +254,7 @@ bool CurseOutput::writeKey(const std::string &key, const std::string &after, std
 
 bool CurseOutput::writeKey(const std::string &key, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags, unsigned int extraLen)
 {
-    if (cursor.second - topleft < 0)
+    if (cursor.second - scrollTop < 0)
     {
         cursor.second++;
         return true;
@@ -268,7 +266,7 @@ bool CurseOutput::writeKey(const std::string &key, std::pair<int, int> &cursor,
     flags.type(OutputFlag::TYPE_OBJ);
     write(": ", maxSize.first, flags);
     flags.type(oldType);
-    return (cursor.second - topleft < 0 || (unsigned)(cursor.second - topleft) <= maxSize.second);
+    return (cursor.second - scrollTop < 0 || (unsigned)(cursor.second - scrollTop) <= maxSize.second);
 }
 
 unsigned int CurseOutput::write(const int &x, const int &y, const JSonElement *item, unsigned int maxWidth, OutputFlag flags)
@@ -278,7 +276,7 @@ unsigned int CurseOutput::write(const int &x, const int &y, const JSonElement *i
 
 unsigned int CurseOutput::write(const int &x, const int &y, const char item, unsigned int maxWidth, OutputFlag flags)
 {
-    int offsetY = y - topleft;
+    int offsetY = y - scrollTop;
     if (offsetY < 0)
         return 1;
     if (flags.selected())
@@ -320,7 +318,7 @@ void CurseOutput::write(const std::string &str, unsigned int maxWidth, const Out
 
 unsigned int CurseOutput::write(const int &x, const int &y, const std::string &str, unsigned int maxWidth, const OutputFlag flags)
 {
-    int offsetY = y - topleft;
+    int offsetY = y - scrollTop;
     if (offsetY < 0)
         return 1;
     move(offsetY, x);
@@ -336,15 +334,15 @@ unsigned int CurseOutput::getNbLines(float nbChar, unsigned int maxWidth)
     return nLine +1;
 }
 
-void CurseOutput::getScreenSize(std::pair<unsigned int, unsigned int> &screenSize) const
+const std::pair<unsigned int, unsigned int> CurseOutput::getScreenSize() const
 {
-    getmaxyx(stdscr, screenSize.second, screenSize.first);
-}
-
-void CurseOutput::getScreenSize(std::pair<unsigned int, unsigned int> &screenSize, std::pair<int, int> &bs) const
-{
-    getScreenSize(screenSize);
+    std::pair<int, int> bs;
+    std::pair<int, int> sc;
+    getmaxyx(stdscr, sc.second, sc.first);
     getbegyx(stdscr, bs.second, bs.first);
+    sc.first -= bs.first;
+    sc.second -= bs.second;
+    return sc;
 }
 
 const OutputFlag CurseOutput::getFlag(const JSonElement *item) const
@@ -366,19 +364,14 @@ const OutputFlag CurseOutput::getFlag(const JSonElement *item) const
     return res;
 }
 
-void CurseOutput::checkSelection(const JSonElement *item, const JSonElement *parent, const std::pair<int, int> &cursor)
+void CurseOutput::checkSelection(const JSonElement *item, const std::pair<int, int> &cursor)
 {
     if (!selectFound)
     {
         if (selection == item)
         {
-            if (cursor.second == topleft)
-                selectIsFirst = true;
-            else if (cursor.second < topleft)
-            {
-                topleft = cursor.second;
-                throw SelectionOutOfRange(); //break and restart painting
-            }
+            if (cursor.second < scrollTop) //Selection is above vp, move scroll pos to selection and start drawing
+                scrollTop = cursor.second;
             selectFound = true;
         }
         else if (!item->getParent() || !dynamic_cast<const JSonObjectEntry*>(item->getParent()))
@@ -418,17 +411,14 @@ bool CurseOutput::readInput()
             case KEY_UP:
             case 'K':
             case 'k':
-                if (selectIsFirst && topleft)
-                    topleft = std::max(topleft -3, 0);
-                else
-                    selection = select_up;
+                selection = select_up;
                 return true;
 
             case KEY_DOWN:
             case 'j':
             case 'J':
                 if (selectIsLast)
-                    topleft += 2;
+                    scrollTop += 2;
                 else if (selection != select_down)
                     selection = select_down;
                 else
@@ -641,8 +631,6 @@ const std::string CurseOutput::search()
     {
         int c;
 
-        clear();
-        redraw();
         writeBottomLine('/' +buffer, OutputFlag::SPECIAL_SEARCH);
         refresh();
         c = getch();
@@ -650,6 +638,7 @@ const std::string CurseOutput::search()
             break;
         else if (c == '\b' || c == 127)
             buffer.pop_back();
+        // TODO check kill-key and throw noInputException
         else
             buffer += c;
     }
@@ -662,8 +651,7 @@ const std::string CurseOutput::search()
 
 void CurseOutput::writeBottomLine(const std::string &buffer, short color) const
 {
-    std::pair<unsigned int, unsigned int> screenSize;
-    getScreenSize(screenSize);
+    const std::pair<unsigned int, unsigned int> screenSize = getScreenSize();
     size_t bufsize = buffer.size();
     if (params.colorEnabled())
         attron(COLOR_PAIR(color));
@@ -712,7 +700,7 @@ void CurseOutput::init()
     signal(SIGINT, _resizeFnc);
     signal(SIGTERM, _resizeFnc);
     signal(SIGKILL, _resizeFnc);
-    topleft = 0;
+    scrollTop = 0;
 }
 
 void CurseOutput::shutdown()

+ 8 - 4
src/jsonException.cpp

@@ -10,11 +10,15 @@
 JsonException::JsonException(const std::string &wh, unsigned long long pos, LinearHistory &h): offset(pos), history(h), _what(wh)
 { }
 
-JsonHexvalueException::JsonHexvalueException(const std::string &what, unsigned long long o, LinearHistory &h): JsonException(what, o, h)
-{ }
+JsonHexvalueException::JsonHexvalueException(const std::string &what, unsigned long long o, LinearHistory &h): JsonFormatException(o, h)
+{
+    _what = what;
+}
 
-JsonHexvalueException::JsonHexvalueException(char c, unsigned long long o, LinearHistory &h): JsonException(JsonHexvalueException::msg(c), o, h)
-{ }
+JsonHexvalueException::JsonHexvalueException(char c, unsigned long long o, LinearHistory &h): JsonFormatException(o, h)
+{
+    _what = JsonHexvalueException::msg(c);
+}
 
 JsonFormatException::JsonFormatException(unsigned long long pos, LinearHistory &h):
     JsonException("invalid value", pos, h)

+ 7 - 11
src/jsonPrimitive.cpp

@@ -15,28 +15,24 @@ template<> JSonPrimitive<int>::~JSonPrimitive() {}
 template<> JSonPrimitive<long long>::~JSonPrimitive() {}
 template<> JSonPrimitive<std::string>::~JSonPrimitive() {}
 
-template<> std::string JSonPrimitive<std::string>::stringify() const
-{
-    return value;
-}
+template<> std::string JSonPrimitive<std::string>::toString() const
+{ return value; }
 
-template<> std::string JSonPrimitive<double>::stringify() const
+template<> std::string JSonPrimitive<double>::toString() const
 {
     return std::to_string(value);
 }
 
-template<> std::string JSonPrimitive<long long>::stringify() const
+template<> std::string JSonPrimitive<long long>::toString() const
 {
     return std::to_string(value);
 }
 
-template<> std::string JSonPrimitive<int>::stringify() const
+template<> std::string JSonPrimitive<int>::toString() const
 {
     return std::to_string(value);
 }
 
-template<> std::string JSonPrimitive<bool>::stringify() const
-{
-    return value ? "true" : "false";
-}
+template<> std::string JSonPrimitive<bool>::toString() const
+{ return value ? "true" : "false"; }
 

+ 23 - 0
src/linearHistory.cpp

@@ -31,6 +31,29 @@ void LinearHistory::put(char item)
 
 void LinearHistory::put(char items[], unsigned int count)
 {
+    if (willReset)
+    {
+        reset();
+        line++;
+        willReset = false;
+    }
+    for (unsigned int i=0; i < count; ++i)
+    {
+        if (items[i] == '\n')
+        {
+            if (i < count -1)
+            {
+                willReset = true;
+                put(&items[i +1], count -i);
+                return;
+            }
+            else
+            {
+                willReset = true;
+                return;
+            }
+        }
+    }
     WrappedBuffer<char, ERROR_HISTORY_LEN>::put(items, count);
 }
 

+ 5 - 6
src/main.cpp

@@ -5,17 +5,16 @@
 **/
 
 #include <iostream>
-#include <typeinfo>
 #include <locale.h>
 #include "streamConsumer.hh"
 #include "curseOutput.hh"
 #include "params.hh"
 #include "jsonException.hh"
 
-void displayException(const Params *params, const JsonException &e)
+void displayException(const Params *params, const std::string &type, const JsonException &e)
 {
     std::string buffer = e.getHistory();
-    std::cerr << params->getProgName() << ": [" << typeid(e).name() << "] at line " << e.currentLine() << " ("  << e.what() << ") while reading" << std::endl;
+    std::cerr << params->getProgName() << ": [" << type << "] at line " << e.currentLine() << " ("  << e.what() << ") while reading" << std::endl;
     std::cerr << buffer << std::endl << std::string(buffer.size() -1, '~') << '^' << std::endl;
 }
 
@@ -37,19 +36,19 @@ void run(Params *params)
     }
     catch (EofException &e)
     {
-        std::cerr << params->getProgName() << ": " << typeid(e).name() << " ("  << e.what() << ") error while reading" << std::endl;
+        std::cerr << params->getProgName() << ": " << Warning::getType(e) << " ("  << e.what() << ") error while reading" << std::endl;
         return;
     }
     catch (JsonException &e)
     {
         std::cerr << "Error: ";
-        displayException(params, e);
+        displayException(params, Warning::getType(e), e);
         return;
     }
     for (Warning w : stream.getMessages())
     {
         std::cerr << "Warning: ";
-        displayException(params, w());
+        displayException(params, w.getType(), w());
     }
     out = new CurseOutput(root, *params);
     out->run();

+ 12 - 13
src/streamConsumer.cpp

@@ -16,10 +16,6 @@ StreamConsumer::~StreamConsumer()
 {
     if (root)
         delete root;
-    for (Warning i : warnings)
-    {
-        delete i.getPtrUnsafe();
-    }
 }
 
 StreamConsumer *StreamConsumer::withConfig(const AParams *p)
@@ -57,10 +53,11 @@ JSonElement *StreamConsumer::readNext(JSonContainer *parent)
     return root;
 }
 
-JSonElement * const StreamConsumer::getRoot() const
-{
-    return root;
-}
+const JSonElement * const StreamConsumer::getRoot() const
+{ return root; }
+
+JSonElement * const StreamConsumer::getRoot()
+{ return root; }
 
 JSonObject *StreamConsumer::readObject(JSonContainer *parent)
 {
@@ -87,7 +84,7 @@ JSonObject *StreamConsumer::readObject(JSonContainer *parent)
             else // add Warning, new key erase previous one
             {
                 result->erase(key->getValue());
-                warnings.push_back(Warning(new JSonObject::DoubleKeyException(stream.tellg(), key->getValue(), history)));
+                warnings.push_back(Warning(JSonObject::DoubleKeyException(stream.tellg(), key->getValue(), history)));
             }
         }
         JSonElement *child = readNext(result);
@@ -285,16 +282,18 @@ static unsigned char hexbyte(const char c)
     throw std::invalid_argument(JsonHexvalueException::msg(c));
 }
 
-static unsigned char hexbyte(const char str[2])
+template<typename T>
+static T hexbyte(const char str[], unsigned int len)
 {
-    unsigned char result = 0;
-    result = (hexbyte(*str) <<4) + hexbyte(str[1]);
+    T result = 0;
+    for (unsigned int i =0; i < len; ++i)
+        result = (result << 4) + hexbyte(str[i]);
     return result;
 }
 
 void StreamConsumer::appendUnicode(const char unicode[4], std::string &buf)
 {
-    unsigned short uni = (hexbyte(unicode) <<8) + hexbyte(unicode+2);
+    unsigned short uni = hexbyte<unsigned short>(unicode, 4);
     char test[5];
     bzero(test, sizeof(*test) *5);
     snprintf(test, 4, "%lc", uni);

+ 11 - 5
src/warning.cpp

@@ -4,17 +4,23 @@
  * Author: isundil <isundill@gmail.com>
 **/
 
+#include <typeinfo>
 #include "warning.hh"
 
-Warning::Warning(const JsonException *w): what(w)
-{ }
+Warning::Warning(const JsonException &w): what(w)
+{
+    type = Warning::getType(w);
+}
 
 Warning::~Warning()
 { }
 
 const JsonException &Warning::operator()() const
-{ return *what; }
-
-const JsonException *Warning::getPtrUnsafe() const
 { return what; }
 
+const std::string &Warning::getType() const
+{ return type; }
+
+std::string Warning::getType(const std::exception &w)
+{ return typeid(w).name(); }
+