소스 검색

[refactor][Fix #14] refactored search

isundil 9 년 전
부모
커밋
36c736a719
12개의 변경된 파일145개의 추가작업 그리고 112개의 파일을 삭제
  1. 2 2
      doc/jsonstroll.1
  2. 12 4
      include/curseOutput.hh
  3. 1 0
      include/jsonException.hh
  4. 0 5
      include/jsonObjectEntry.hh
  5. 7 0
      include/outputFlag.hh
  6. 83 94
      src/curseOutput.cpp
  7. 1 0
      src/jsonElement.cpp
  8. 3 0
      src/jsonException.cpp
  9. 0 6
      src/jsonObjectEntry.cpp
  10. 1 1
      src/main.cpp
  11. 12 0
      src/outputFlag.cpp
  12. 23 0
      test/testObject.json

+ 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" "July 2016" "jsonstroll (jsonstroller suite) 1.0RC1 generated on Jul 31 2016" "User Commands"
+.TH JSONSTROLL "1" "August 2016" "jsonstroll (jsonstroller suite) 1.0RC1 generated on Aug  6 2016" "User Commands"
 .SH NAME
-jsonstroll \- manual page for jsonstroll (jsonstroller suite) 1.0RC1 generated on Jul 31 2016
+jsonstroll \- manual page for jsonstroll (jsonstroller suite) 1.0RC1 generated on Aug  6 2016
 .SH SYNOPSIS
 .B jsonstroll
 [\fI\,OPTIONS\/\fR] [\fI\,--\/\fR] \fI\,INPUT\/\fR

+ 12 - 4
include/curseOutput.hh

@@ -109,12 +109,19 @@ class CurseOutput
          * 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);
+        bool jumpToNextSearch(const JSonElement *initial_selection, bool &);
+        bool jumpToNextSearch();
+
         /**
          * prompt for user input, and return it
          * @throws noInputException if user use a kill-key (to exit buffer)
         **/
-        const std::string search();
+        const std::string inputSearch();
+        /**
+         * find occurences of search result and fill this#search_result
+        **/
+        unsigned int search(const std::string &, const JSonElement *);
+
         /**
          * Write a message on the last line, using color
         **/
@@ -141,9 +148,10 @@ class CurseOutput
         **/
         const JSonElement *selection;
         /**
-         * currently searching pattern
+         * currently searching pattern and its results
         **/
-        std::string search_pattern;
+        std::list<const JSonElement*> search_result;
+
         /**
          * prev/next items to be selected on up/down keys
         **/

+ 1 - 0
include/jsonException.hh

@@ -28,6 +28,7 @@ class JsonException: public std::exception
         const char *what() const noexcept;
 
         unsigned int currentLine() const;
+        unsigned int currentCol() const;
 
     protected:
         const unsigned long long offset;

+ 0 - 5
include/jsonObjectEntry.hh

@@ -25,11 +25,6 @@ class JSonObjectEntry: public JSonElement
         const JSonElement *operator*() const;
         JSonElement *operator*();
 
-        /**
-         * check if key or value match search pattern
-        **/
-        bool match(const std::string &) const;
-
     protected:
         const std::string key;
         JSonElement * const value;

+ 7 - 0
include/outputFlag.hh

@@ -18,6 +18,12 @@ class OutputFlag
         bool selected() const;
         bool selected(bool v);
 
+        /**
+         * get/set SEARCH byte
+        **/
+        bool searched() const;
+        bool searched(bool v);
+
         /**
          * get/set item's type
         **/
@@ -36,6 +42,7 @@ class OutputFlag
 
     public:
         static const short MODE_SELECTED = 1;
+        static const short MODE_SEARCHED = 2;
 
         static const char TYPE_UNKNOWN;
         static const char TYPE_STRING;

+ 83 - 94
src/curseOutput.cpp

@@ -7,9 +7,11 @@
 #include <iostream>
 
 #include <sys/ioctl.h>
+#include <algorithm>
 #include <unistd.h>
 #include <signal.h>
 #include <string.h>
+#include <stack>
 
 #include "curseOutput.hh"
 #include "jsonPrimitive.hh"
@@ -276,13 +278,14 @@ 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 - scrollTop;
+    char color = OutputFlag::SPECIAL_NONE;
+
     if (offsetY < 0)
         return 1;
+
     if (flags.selected())
         attron(A_REVERSE | A_BOLD);
-    char color = OutputFlag::SPECIAL_NONE;
-
-    if (params.colorEnabled() && search_pattern.size() == 1 && search_pattern.c_str()[0] == item)
+    if (flags.searched())
         color = OutputFlag::SPECIAL_SEARCH;
     else if (colors.find(flags.type()) != colors.end())
         color = flags.type();
@@ -299,15 +302,14 @@ unsigned int CurseOutput::write(const int &x, const int &y, const char item, uns
 void CurseOutput::write(const std::string &str, const OutputFlag flags) const
 {
     char color = OutputFlag::SPECIAL_NONE;
-    if (params.colorEnabled() && !search_pattern.empty() && str.find(search_pattern) != str.npos)
+    if (flags.selected())
+        attron(A_REVERSE | A_BOLD);
+    if (flags.searched())
         color = OutputFlag::SPECIAL_SEARCH;
     else if (colors.find(flags.type()) != colors.end())
         color = flags.type();
-
     if (color != OutputFlag::SPECIAL_NONE)
         attron(COLOR_PAIR(color));
-    if (flags.selected())
-        attron(A_REVERSE | A_BOLD);
 
     printw("%s", str.c_str());
     attroff(A_REVERSE | A_BOLD);
@@ -350,6 +352,7 @@ const OutputFlag CurseOutput::getFlag(const JSonElement *item) const
     const JSonElement *i = dynamic_cast<const JSonObjectEntry*>(item) ? **((const JSonObjectEntry*)item) : item;
 
     res.selected(item == selection);
+    res.searched(std::find(search_result.cbegin(), search_result.cend(), item) != search_result.cend());
     if (dynamic_cast<const JSonPrimitive<std::string> *>(i))
         res.type(OutputFlag::TYPE_STRING);
     else if (dynamic_cast<const JSonPrimitive<bool> *>(i))
@@ -497,116 +500,99 @@ bool CurseOutput::readInput()
             }
 
             case '/':
-                search_pattern = search();
+            {
+                const std::string search_pattern = inputSearch();
+                search_result.clear();
+                if (search_pattern.empty())
+                    return true;
+                search(search_pattern, data);
+            }
 
             case 'n':
             case 'N':
-                jumpToNextSearch(true, true, selection);
-                // jumpToNextSearch have its own redraw, so no need to return true here
+                if (search_result.empty())
+                    this->redraw("Pattern not found");
+                else if (jumpToNextSearch())
+                    return true;
                 break;
         }
     }
     return false;
 }
 
-//TODO move to JSonElement ?
-bool CurseOutput::jumpToNextSearch(bool scanParent, bool redraw, const JSonElement *initial_selection)
+unsigned int CurseOutput::search(const std::string &search_pattern, const JSonElement *current)
 {
-    bool found = false;
-    const JSonElement *current = selection;
-    const JSonElement *prev = nullptr;
+    const JSonContainer *container = dynamic_cast<const JSonContainer *> (current);
+    const JSonObjectEntry *objEntry = dynamic_cast<const JSonObjectEntry *> (current);
+    unsigned int result =0;
 
-    while (current && !found)
+    if (container)
     {
-        if (dynamic_cast<const JSonContainer *> (current) == nullptr)
-        {
-            //ObjectEntry or Primitive
-            const JSonElement* entryChild = nullptr;
-            char isObjectEntry = 0;
-            if (dynamic_cast<const JSonObjectEntry *>(current) != nullptr)
-            {
-                entryChild = **((const JSonObjectEntry*)current);
-                if (dynamic_cast<const JSonContainer *> (entryChild) == nullptr)
-                    isObjectEntry = 1;
-                else
-                    isObjectEntry = 2;
-            }
-            const std::string str = current->stringify();
-            std::string strEntry;
-            if (isObjectEntry == 1)
-                strEntry = entryChild->stringify();
-            if (current != initial_selection && entryChild != initial_selection && current->match(search_pattern))
-            {
-                selection = current;
-                found = true;
-                break;
-            }
-            if (isObjectEntry == 2)
-            {
-                const JSonElement *_selection = selection;
-                selection = entryChild;
-                if (jumpToNextSearch(false, false, initial_selection))
-                {
-                    found = true;
-                    break;
-                }
-                selection = _selection;
-            }
-        }
-        else
+        if (!container->empty())
+            for (const JSonElement *it : *container)
+                result += search(search_pattern, it);
+    }
+    else
+    {
+        if (current && current->match(search_pattern))
         {
-            //Object or array
-            for (const JSonElement *i : *(const JSonContainer*)current)
+            if (current->getParent() && dynamic_cast<const JSonObjectEntry*>(current->getParent()))
             {
-                if (prev != nullptr)
-                {
-                    if (prev != i)
-                        continue;
-                    else
-                    {
-                        prev = nullptr;
-                        continue;
-                    }
-                }
-                const JSonElement *_selection = selection;
-                selection = i;
-                if (jumpToNextSearch(false, false, initial_selection))
-                {
-                    found = true;
-                    break;
-                }
-                selection = _selection;
+                if (current->getParent() != selection)
+                    search_result.push_back(current->getParent());
             }
+            else
+                search_result.push_back(current);
+            result++;
         }
-        if (!scanParent)
-            break;
-        prev = current;
-        current = current->getParent();
+        if (objEntry)
+            result += search(search_pattern, **objEntry);
     }
-    bool foundAfterLoop = false;
-    if (!found && scanParent && selection != data)
+    result = search_result.size();
+    return result;
+}
+
+bool CurseOutput::jumpToNextSearch(const JSonElement *current, bool &selectFound)
+{
+    const JSonContainer *container = dynamic_cast<const JSonContainer *> (current);
+    const JSonObjectEntry *objEntry = dynamic_cast<const JSonObjectEntry *> (current);
+
+    if (selection == current)
+        selectFound = true;
+    if (container)
     {
-        const JSonElement *_selection = selection;
-        selection = data;
-        if (jumpToNextSearch(false, false, initial_selection))
-            foundAfterLoop = true;
-        else
-            selection = _selection;
+        if (!container->empty())
+            for (const JSonElement *it : *container)
+                if (jumpToNextSearch(it, selectFound))
+                    return true;
     }
-    if (!redraw)
-        return found;
-    if (foundAfterLoop || (!found && selection->match(search_pattern)))
+    else
     {
-        this->redraw("Search hit BOTTOM, continuing at TOP");
-        return true;
+        if (current && std::find(search_result.cbegin(), search_result.cend(), current) != search_result.cend() && current != selection && selectFound)
+        {
+            selection = current;
+            return true;
+        }
+        if (objEntry)
+            if (jumpToNextSearch(**objEntry, selectFound))
+                return true;
     }
-    if (!found)
+    return false;
+}
+
+bool CurseOutput::jumpToNextSearch()
+{
+    bool selectFound = false;
+    bool res = jumpToNextSearch(data, selectFound);
+
+    if (!res)
     {
-        this->redraw("Pattern not found");
+        selection = *(search_result.cbegin());
+        unfold(selection);
+        redraw("Search hit BOTTOM, continuing at TOP");
         return false;
     }
     unfold(selection);
-    this->redraw();
     return true;
 }
 
@@ -619,7 +605,7 @@ void CurseOutput::unfold(const JSonElement *item)
     }
 }
 
-const std::string CurseOutput::search()
+const std::string CurseOutput::inputSearch()
 {
     std::string buffer;
 
@@ -636,7 +622,10 @@ const std::string CurseOutput::search()
         if (c == '\n')
             break;
         else if (c == '\b' || c == 127)
-            buffer.pop_back();
+        {
+            if (!buffer.empty())
+                buffer.pop_back();
+        }
         // TODO check kill-key and throw noInputException
         else
             buffer += c;

+ 1 - 0
src/jsonElement.cpp

@@ -82,3 +82,4 @@ bool JSonElement::match(const std::string &search_pattern) const
     const std::string str = stringify();
     return str.find(search_pattern) != str.npos;
 }
+

+ 3 - 0
src/jsonException.cpp

@@ -45,6 +45,9 @@ std::string JsonHexvalueException::msg(char c)
 unsigned int JsonException::currentLine() const
 { return history.currentLine(); }
 
+unsigned int JsonException::currentCol() const
+{ return history.totalSize(); }
+
 std::string JsonException::getHistory() const
 { return history.toString(); }
 

+ 0 - 6
src/jsonObjectEntry.cpp

@@ -37,12 +37,6 @@ std::string JSonObjectEntry::stringify() const
     return key;
 }
 
-bool JSonObjectEntry::match(const std::string &search_pattern) const
-{
-    const std::string strEntry = (**this)->stringify();
-    return JSonElement::match(search_pattern) || strEntry.find(search_pattern) != strEntry.npos;
-}
-
 /*
 const JSonElement *JSonObjectEntry::findPrev() const
 {

+ 1 - 1
src/main.cpp

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

+ 12 - 0
src/outputFlag.cpp

@@ -36,6 +36,18 @@ bool OutputFlag::selected(bool v)
     return v;
 }
 
+bool OutputFlag::searched() const
+{ return mode & OutputFlag::MODE_SEARCHED; }
+
+bool OutputFlag::searched(bool v)
+{
+    if (v)
+        mode |= OutputFlag::MODE_SEARCHED;
+    else
+        mode &= ~OutputFlag::MODE_SEARCHED;
+    return v;
+}
+
 char OutputFlag::type() const
 { return _type; }
 

+ 23 - 0
test/testObject.json

@@ -0,0 +1,23 @@
+{
+    "0":"897316929176464ebc9ad085f31e7284",
+    "1":"b026324c6904b2a9cb4b88d6d61c81d1",
+    "2":"26ab0db90d72e28ad0ba1e22ee510510",
+    "3":"6d7fce9fee471194aa8b5b6e47267f03",
+    "4":"48a24b70a0b376535542b996af517398",
+    "5":"1dcca23355272056f04fe8bf20edfce0",
+    "6":"9ae0ea9e3c9c6e1b9b6252c8395efdc1",
+    "7":"84bc3da1b3e33a18e8d5e1bdd7a18d7a",
+    "8":"c30f7472766d25af1dc80b3ffc9a58c7",
+    "9":"7c5aba41f53293b712fd86d08ed5b36e",
+    "10":"31d30eea8d0968d6458e0ad0027c9f80",
+    "11":"166d77ac1b46a1ec38aa35ab7e628ab5",
+    "12":"2737b49252e2a4c0fe4c342e92b13285",
+    "13":"aa6ed9e0f26a6eba784aae8267df1951",
+    "14":"367764329430db34be92fd14a7a770ee",
+    "15":"8c9eb686bf3eb5bd83d9373eadf6504b",
+    "16":"5b6b41ed9b343fed9cd05a66d36650f0",
+    "17":"4d095eeac8ed659b1ce69dcef32ed0dc",
+    "18":"cf4278314ef8e4b996e1b798d8eb92cf",
+    "19":"3bb50ff8eeb7ad116724b56a820139fa",
+    "20":"dbbf8220893d497d403bb9cdf49db7a4"
+}