Selaa lähdekoodia

Merge branch 'jsonstroller'

isundil 9 vuotta sitten
vanhempi
commit
e4b5e559ee

+ 2 - 2
doc/jsonstroll.1

@@ -1,7 +1,7 @@
 .\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.47.3.
-.TH JSONSTROLL "1" "August 2016" "jsonstroll (jsonstroller suite) 1.0RC1 generated on Aug 15 2016" "User Commands"
+.TH JSONSTROLL "1" "August 2016" "jsonstroll (jsonstroller suite) 1.0RC1 generated on Aug 16 2016" "User Commands"
 .SH NAME
-jsonstroll \- manual page for jsonstroll (jsonstroller suite) 1.0RC1 generated on Aug 15 2016
+jsonstroll \- manual page for jsonstroll (jsonstroller suite) 1.0RC1 generated on Aug 16 2016
 .SH SYNOPSIS
 .B jsonstroll
 [\fI\,OPTIONS\/\fR]

+ 9 - 8
include/curseOutput.hh

@@ -65,7 +65,7 @@ class CurseOutput
         /**
          * redraw item and children
         **/
-        bool redraw(std::pair<int, int> &, const std::pair<unsigned int, unsigned int> &maxWidth, const JSonElement *item);
+        bool redraw(std::pair<int, int> &, const std::pair<unsigned int, unsigned int> &maxWidth, JSonElement *item);
 
         /**
          * Wait for input
@@ -89,7 +89,7 @@ class CurseOutput
          * @param @maxWidth screen width
          * @return the number of line written
         **/
-        static unsigned int getNbLines(float nbChar, unsigned int maxWidth);
+        static unsigned int getNbLines(const size_t nbChar, unsigned int maxWidth);
 
         /**
          * get flags to be passed to write.
@@ -104,13 +104,14 @@ class CurseOutput
          * Warning: this one does not check line height, because he's not aware of cursor position
         **/
         void write(const std::string &str, 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);
+        unsigned int write(const int &x, const int &y, JSonElement *item, unsigned int maxWidth, const OutputFlag);
+        unsigned int write(const int &x, const int &y, const std::string &item, const size_t len, unsigned int maxWidth, const OutputFlag);
         unsigned int write(const int &x, const int &y, const char item, unsigned int maxWidth, const OutputFlag);
-        bool writeKey(const std::string &key, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag, unsigned int extraLen =0);
-        bool writeKey(const std::string &key, const std::string &after, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag);
+        bool writeKey(const std::string &key, const size_t keylen, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag, unsigned int extraLen =0);
+        bool writeKey(const std::string &key, const size_t keylen, const std::string &after, const size_t afterlen, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag);
+        bool writeKey(const std::string &key, const size_t keylen, const std::string &after, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxWidth, OutputFlag);
         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);
+        bool writeContent(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, std::list<JSonElement *> * obj);
 
         /**
          * find next search occurence and select it (wich cause viewport to move, eventually)
@@ -151,7 +152,7 @@ class CurseOutput
         /**
          * Root item
         **/
-        const JSonElement *data;
+        JSonElement * const data;
 
         /**
          * selected item

+ 9 - 0
include/jsonElement.hh

@@ -21,6 +21,13 @@ class JSonElement
          * return string-representative of this JSonElement
         **/
         virtual std::string stringify() const =0;
+
+        /**
+         * get the number of col string will output
+        **/
+        virtual size_t strlen() const;
+        virtual size_t lazystrlen();
+
         /**
          * return number of parents this item has
         **/
@@ -56,5 +63,7 @@ class JSonElement
          * Not a JSonContainer because JSonObjectEntry can be a parent and isn't a JSonContainer either
         **/
         JSonElement *parent;
+
+        size_t _strlen;
 };
 

+ 3 - 0
include/searchPattern.hh

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <string>
+#include <regex>
 
 class JSonElement;
 
@@ -22,12 +23,14 @@ class SearchPattern
         void evalFlags(const char *);
 
         std::string pattern;
+        std::regex *regex;
         short flags;
         short typeFlag;
 
         static const short FLAG_CASE;
         static const short FLAG_WHOLEWORD;
         static const short FLAG_WHOLESTR;
+        static const short FLAG_REGEX;
 
         static const short TYPE_BOOL;
         static const short TYPE_NUMBER;

+ 38 - 28
src/curseOutput.cpp

@@ -130,7 +130,7 @@ 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)
+bool CurseOutput::redraw(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, JSonElement *item)
 {
     checkSelection(item, cursor);
     if (dynamic_cast<const JSonContainer*>(item))
@@ -160,24 +160,24 @@ bool CurseOutput::writeContainer(std::pair<int, int> &cursor, const std::pair<un
     {
         std::string ss;
         ss.append(&childDelimiter[0], 1).append(" ... ").append(&childDelimiter[1], 1);
-        cursor.second += write(cursor.first, cursor.second, ss, maxSize.first, getFlag(item));
+        cursor.second += write(cursor.first, cursor.second, ss, 7, maxSize.first, getFlag(item));
     }
     else
     {
         cursor.second += write(cursor.first, cursor.second, childDelimiter[0], maxSize.first, getFlag(item));
         if (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1)
                 return false;
-        if (!writeContent(cursor, maxSize, (const std::list<JSonElement *> *)item))
+        if (!writeContent(cursor, maxSize, (std::list<JSonElement *> *)item))
             return false;
         cursor.second += write(cursor.first, cursor.second, childDelimiter[1], maxSize.first, getFlag(item));
     }
     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)
+bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, std::list<JSonElement*> *_item)
 {
-    const JSonContainer *item = (const JSonContainer *)_item;
-    bool containerIsObject = (dynamic_cast<const JSonObject *>(item) != nullptr);
+    JSonContainer *item = (JSonContainer *)_item;
+    bool containerIsObject = (dynamic_cast<JSonObject *>(item) != nullptr);
     bool result = true;
     cursor.first += INDENT_LEVEL;
 
@@ -187,37 +187,38 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
         if (containerIsObject)
         {
             JSonObjectEntry *ent = (JSonObjectEntry*) i;
-            bool isContainer = (dynamic_cast<const JSonContainer *>(**ent) != nullptr);
+            bool isContainer = (dynamic_cast<JSonContainer *>(**ent) != nullptr);
             std::string key = ent->stringify();
             checkSelection(ent, cursor);
-            if (isContainer && collapsed.find((const JSonContainer*)(**ent)) != collapsed.cend())
+            if (isContainer && collapsed.find((JSonContainer*)(**ent)) != collapsed.cend())
             {
-                if (dynamic_cast<const JSonObject *>(**ent))
+                if (dynamic_cast<JSonObject *>(**ent))
                 {
-                    if (!writeKey(key, "{ ... }", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                    if (!writeKey(key, ent->lazystrlen(), "{ ... }", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                         break;
                 }
-                else if (!writeKey(key, "[ ... ]", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                else if (!writeKey(key, ent->lazystrlen(), "[ ... ]", 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 - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                JSonElement *eContent = **ent;
+                if (!writeKey(key, ent->lazystrlen(), eContent->stringify(), eContent->lazystrlen(), cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                     break;
             }
             else if (((JSonContainer*)(**ent))->size() == 0)
             {
                 if (dynamic_cast<const JSonObject *>(**ent) )
                 {
-                    if (!writeKey(key, "{ }", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                    if (!writeKey(key, ent->lazystrlen(), "{ }", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                         break;
                 }
-                else if (!writeKey(key, "[ ]", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
+                else if (!writeKey(key, ent->lazystrlen(), "[ ]", cursor, maxSize, getFlag(ent)) || (cursor.second - scrollTop > 0 && (unsigned)(cursor.second - scrollTop) > maxSize.second -1))
                     break;
             }
             else
             {
-                if (!writeKey(key, cursor, maxSize, getFlag(ent)))
+                if (!writeKey(key, ent->lazystrlen(), cursor, maxSize, getFlag(ent)))
                     break;
                 const JSonElement *saveSelection = selection;
                 if (selection == ent)
@@ -245,21 +246,30 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
     return result;
 }
 
-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)
+bool CurseOutput::writeKey(const std::string &key, const size_t keylen, const std::string &after, size_t afterlen, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags)
 {
     if (cursor.second - scrollTop < 0)
     {
         cursor.second++;
         return true;
     }
-    if (!writeKey(key, cursor, maxSize, flags, after.size()))
-        return false;
+    char oldType = flags.type();
+    flags.type(OutputFlag::TYPE_OBJKEY);
+    write(cursor.first, cursor.second, key, 0, 1, flags);
+    flags.type(OutputFlag::TYPE_OBJ);
+    write(": ", flags);
+    flags.type(oldType);
     write(after.c_str(), flags);
-    //TODO check result if write goes to new line
-    return true;
+    cursor.second += getNbLines(cursor.first +keylen +2 +afterlen, maxSize.first);
+    return (cursor.second - scrollTop < 0 || (unsigned)(cursor.second - scrollTop) <= maxSize.second);
+}
+
+bool CurseOutput::writeKey(const std::string &key, const size_t keylen, const std::string &after, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags)
+{
+    return writeKey(key, keylen, after, after.size(), cursor, maxSize, flags);
 }
 
-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)
+bool CurseOutput::writeKey(const std::string &key, const size_t keylen, std::pair<int, int> &cursor, const std::pair<unsigned int, unsigned int> &maxSize, OutputFlag flags, unsigned int extraLen)
 {
     if (cursor.second - scrollTop < 0)
     {
@@ -268,16 +278,16 @@ bool CurseOutput::writeKey(const std::string &key, std::pair<int, int> &cursor,
     }
     char oldType = flags.type();
     flags.type(OutputFlag::TYPE_OBJKEY);
-    cursor.second += write(cursor.first, cursor.second, key, maxSize.first -extraLen -2, flags);
+    cursor.second += write(cursor.first, cursor.second, key, keylen, maxSize.first -extraLen -2, flags);
     flags.type(OutputFlag::TYPE_OBJ);
     write(": ", flags);
     flags.type(oldType);
     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)
+unsigned int CurseOutput::write(const int &x, const int &y, JSonElement *item, unsigned int maxWidth, OutputFlag flags)
 {
-    return write(x, y, item->stringify(), maxWidth, flags);
+    return write(x, y, item->stringify(), item->lazystrlen(), maxWidth, flags);
 }
 
 unsigned int CurseOutput::write(const int &x, const int &y, const char item, unsigned int maxWidth, OutputFlag flags)
@@ -322,19 +332,19 @@ void CurseOutput::write(const std::string &str, const OutputFlag flags) const
         attroff(COLOR_PAIR(color));
 }
 
-unsigned int CurseOutput::write(const int &x, const int &y, const std::string &str, unsigned int maxWidth, const OutputFlag flags)
+unsigned int CurseOutput::write(const int &x, const int &y, const std::string &str, const size_t strlen, unsigned int maxWidth, const OutputFlag flags)
 {
     int offsetY = y - scrollTop;
     if (offsetY < 0)
         return 1;
     move(offsetY, x);
     write(str, flags);
-    return getNbLines(str.size() +x, maxWidth);
+    return getNbLines(strlen +x, maxWidth);
 }
 
-unsigned int CurseOutput::getNbLines(float nbChar, unsigned int maxWidth)
+unsigned int CurseOutput::getNbLines(const size_t nbChar, unsigned int maxWidth)
 {
-    float nLine = nbChar / maxWidth;
+    double nLine = (double) nbChar / maxWidth;
     if (nLine == (unsigned int) nLine)
         return nLine;
     return nLine +1;

+ 25 - 1
src/jsonElement.cpp

@@ -9,7 +9,7 @@
 #include "jsonObjectEntry.hh"
 #include "searchPattern.hh"
 
-JSonElement::JSonElement(JSonElement *p): parent(p)
+JSonElement::JSonElement(JSonElement *p): parent(p), _strlen(0)
 { }
 
 JSonElement::~JSonElement()
@@ -20,6 +20,30 @@ void JSonElement::setParent(JSonElement *p)
     parent = p;
 }
 
+size_t JSonElement::lazystrlen()
+{
+    if (_strlen)
+        return _strlen;
+    const std::string buf = stringify();
+    if (!buf.size())
+        return _strlen;
+    wchar_t wbuf[buf.size()];
+    mbstowcs(wbuf, buf.c_str(), buf.size() * sizeof(wchar_t));
+    return _strlen = wcslen(wbuf);
+}
+
+size_t JSonElement::strlen() const
+{
+    if (_strlen)
+        return _strlen;
+    const std::string buf = stringify();
+    if (!buf.size())
+        return _strlen;
+    wchar_t wbuf[buf.size()];
+    mbtowc(wbuf, buf.c_str(), buf.size());
+    return wcslen(wbuf);
+}
+
 unsigned int JSonElement::getLevel() const
 {
     unsigned int level = 0;

+ 23 - 7
src/searchPattern.cpp

@@ -1,11 +1,12 @@
 #include <algorithm>
 #include <sstream>
-#include "searchPattern.hh"
+#include <regex>
 
+#include "searchPattern.hh"
 #include "jsonObjectEntry.hh"
 #include "jsonPrimitive.hh"
 
-SearchPattern::SearchPattern(const std::string &input): flags(0)
+SearchPattern::SearchPattern(const std::string &input): regex(nullptr), flags(0)
 {
     size_t pos = 0;
     bool escaped = false;
@@ -37,7 +38,10 @@ SearchPattern::SearchPattern(const std::string &input): flags(0)
 }
 
 SearchPattern::~SearchPattern()
-{ }
+{
+    if (regex)
+        delete regex;
+}
 
 void SearchPattern::evalFlags(const char *s)
 {
@@ -48,6 +52,12 @@ void SearchPattern::evalFlags(const char *s)
             flags |= SearchPattern::FLAG_CASE;
             std::transform(pattern.begin(), pattern.end(), pattern.begin(), ::tolower);
         }
+        else if (*s == 'w')
+            flags |= SearchPattern::FLAG_WHOLEWORD;
+        else if (*s == 'f')
+            flags |= SearchPattern::FLAG_WHOLESTR;
+        else if (*s == 'e')
+            flags |= SearchPattern::FLAG_REGEX;
         else if (*s == 'b')
             typeFlag = SearchPattern::TYPE_BOOL;
         else if (*s == 'n')
@@ -56,12 +66,15 @@ void SearchPattern::evalFlags(const char *s)
             typeFlag = SearchPattern::TYPE_STRING;
         else if (*s == 'o')
             typeFlag = SearchPattern::TYPE_OBJKEY;
-        else if (*s == 'w')
-            flags |= SearchPattern::FLAG_WHOLEWORD;
-        else if (*s == 'f')
-            flags |= SearchPattern::FLAG_WHOLESTR;
         s++;
     }
+    if (!regex && flags & SearchPattern::FLAG_REGEX)
+    {
+        std::regex_constants::syntax_option_type opts = std::regex_constants::ECMAScript;
+        if (flags & FLAG_CASE)
+            opts |= std::regex_constants::icase;
+        regex = new std::regex(pattern, opts);
+    }
 }
 
 bool SearchPattern::isEmpty() const
@@ -92,6 +105,8 @@ bool SearchPattern::match(const std::string &str, const JSonElement *type) const
                 !(dynamic_cast<const JSonPrimitive<long long> *>(type)))
             return false;
     }
+    if (flags & FLAG_REGEX)
+        return regex_search(str, *regex);
     if ((flags & FLAG_WHOLESTR && str.length() != pattern.length())
             || pattern.length() > str.length())
         return false;
@@ -106,6 +121,7 @@ bool SearchPattern::match(const std::string &str, const JSonElement *type) const
 const short SearchPattern::FLAG_CASE        = 1;
 const short SearchPattern::FLAG_WHOLEWORD   = 2;
 const short SearchPattern::FLAG_WHOLESTR    = 4;
+const short SearchPattern::FLAG_REGEX       = 8;
 
 const short SearchPattern::TYPE_BOOL        = 1;
 const short SearchPattern::TYPE_NUMBER      = 2;

+ 1 - 1
src/streamConsumer.cpp

@@ -361,7 +361,7 @@ void StreamConsumer::appendUnicode(const char unicode[4], std::stringstream &buf
     char test[5];
     bzero(test, sizeof(*test) *5);
     snprintf(test, 4, "%lc", uni);
-    buf.write(test, 4);
+    buf.write(test, 3);
 }
 
 std::string StreamConsumer::extractUnicode(const char *buf)

+ 6 - 1
test/testUnicode.json

@@ -1,5 +1,10 @@
 [
+    "_\u20ac_\u20ac_",
+    "Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa",
+    "В чащах юга жил бы цитрус? Да, но фальшивый экземпляр! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!",
     "ascii-only",
     "\u058e",
-    "\u20ac"
+    {
+        "eurooooooooooooooooooooooooooo": "\u20ac coucou"
+    }
 ]