Skip to content

Commit

Permalink
[Big rock]: Feature - navigate on click/double click (#200)
Browse files Browse the repository at this point in the history
* Explore navigation on click

* Re draw tree view on compress/format/sort validate etc.

* Fix memory leak
  • Loading branch information
SinghRajenM authored Oct 19, 2024
1 parent c406080 commit ed7909c
Show file tree
Hide file tree
Showing 13 changed files with 322 additions and 50 deletions.
24 changes: 15 additions & 9 deletions src/NppJsonViewer/JsonHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <rapidjson/error/en.h>

#include "Define.h"
#include "TrackingStream.h"

namespace rj = rapidjson;

Expand Down Expand Up @@ -42,7 +43,7 @@ class JsonHandler
auto ValidateJson(const std::string& jsonText) -> const Result;

template <unsigned format, typename Handler>
auto ParseJson(const std::string& jsonText, rj::StringBuffer& sb, Handler& handler) -> const Result;
auto ParseJson(const std::string& jsonText, rj::StringBuffer& sb, Handler& handler, TrackingStreamSharedPtr pTS = nullptr) -> const Result;

private:
void SortJsonObject(rj::Value& jsonObject, rj::Document::AllocatorType& allocator) const;
Expand All @@ -51,13 +52,18 @@ class JsonHandler
};

template <unsigned flgBase, typename Handler>
inline auto JsonHandler::ParseJson(const std::string& jsonText, rj::StringBuffer& sb, Handler& handler) -> const Result
inline auto JsonHandler::ParseJson(const std::string& jsonText, rj::StringBuffer& sb, Handler& handler, TrackingStreamSharedPtr pTS) -> const Result
{
Result retVal {};

bool success = false;
rj::Reader reader;
rj::StringStream ss(jsonText.c_str());
bool success = false;
rj::Reader reader;

std::shared_ptr<rj::StringStream> pSS = nullptr;
if (!pTS)
{
pSS = std::make_shared<rj::StringStream>(jsonText.c_str());
}

// TODO: Find some better way
constexpr auto flgBase_comment = flgBase | rj::kParseCommentsFlag;
Expand All @@ -66,22 +72,22 @@ inline auto JsonHandler::ParseJson(const std::string& jsonText, rj::StringBuffer

if (m_parseOptions.bIgnoreComment && m_parseOptions.bIgnoreTrailingComma)
{
success = reader.Parse<flgBase_Both>(ss, handler) && sb.GetString();
success = pTS ? reader.Parse<flgBase_Both>(*pTS, handler) && sb.GetString() : reader.Parse<flgBase_Both>(*pSS, handler) && sb.GetString();
}

else if (!m_parseOptions.bIgnoreComment && m_parseOptions.bIgnoreTrailingComma)
{
success = reader.Parse<flgBase_comma>(ss, handler) && sb.GetString();
success = pTS ? reader.Parse<flgBase_comma>(*pTS, handler) && sb.GetString() : reader.Parse<flgBase_comma>(*pSS, handler) && sb.GetString();
}

else if (m_parseOptions.bIgnoreComment && !m_parseOptions.bIgnoreTrailingComma)
{
success = reader.Parse<flgBase_comment>(ss, handler) && sb.GetString();
success = pTS ? reader.Parse<flgBase_comment>(*pTS, handler) && sb.GetString() : reader.Parse<flgBase_comment>(*pSS, handler) && sb.GetString();
}

else if (!m_parseOptions.bIgnoreComment && !m_parseOptions.bIgnoreTrailingComma)
{
success = reader.Parse<flgBase>(ss, handler) && sb.GetString();
success = pTS ? reader.Parse<flgBase>(*pTS, handler) && sb.GetString() : reader.Parse<flgBase>(*pSS, handler) && sb.GetString();
}

if (success)
Expand Down
25 changes: 24 additions & 1 deletion src/NppJsonViewer/JsonNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,32 @@ enum class JsonNodeType : short
OBJECT,
};

struct Position
{
size_t nLine {};
size_t nColumn {};

void clear()
{
nLine = nColumn = 0;
}
};

struct JsonKey
{
Position pos {};
std::string strKey;

void clear()
{
pos.clear();
strKey.clear();
}
};

struct JsonNode
{
std::string key;
JsonKey key;
std::string value;
JsonNodeType type = JsonNodeType::UNKNOWN;
};
76 changes: 63 additions & 13 deletions src/NppJsonViewer/JsonViewDlg.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#include <format>
#include <regex>

#include "JsonViewDlg.h"
#include "Define.h"
#include "Utility.h"
#include "StringHelper.h"
#include "RapidJsonHandler.h"
#include "ScintillaEditor.h"
#include "Profile.h"
#include <format>
#include <regex>


constexpr int FILENAME_LEN_IN_TITLE = 16;

Expand Down Expand Up @@ -100,6 +102,8 @@ void JsonViewDlg::FormatJson()

ReportError(res);
}

ReDrawJsonTree();
}

void JsonViewDlg::CompressJson()
Expand Down Expand Up @@ -130,6 +134,8 @@ void JsonViewDlg::CompressJson()

ReportError(res);
}

ReDrawJsonTree();
}

void JsonViewDlg::SortJsonByKey()
Expand Down Expand Up @@ -162,6 +168,8 @@ void JsonViewDlg::SortJsonByKey()

ReportError(res);
}

ReDrawJsonTree();
}

bool JsonViewDlg::CheckForTokenUndefined(eMethod method, std::string selectedText, Result& res, HTREEITEM tree_root)
Expand All @@ -171,14 +179,8 @@ bool JsonViewDlg::CheckForTokenUndefined(eMethod method, std::string selectedTex
if (m_pSetting->parseOptions.bReplaceUndefined)
{
auto text = selectedText.substr(res.error_pos, 9);
std::transform(
text.begin(),
text.end(),
text.begin(),
[](unsigned char c)
{
return (unsigned char)std::tolower(c);
});
StringHelper::ToLower(text);

if (text == "undefined")
{
try
Expand Down Expand Up @@ -217,7 +219,7 @@ bool JsonViewDlg::CheckForTokenUndefined(eMethod method, std::string selectedTex
else
{
m_pEditor->ReplaceSelection(text);
m_pEditor->MakeSelection(m_pEditor->GetSelectionStart(), static_cast<int>(text.length()));
m_pEditor->MakeSelection(m_pEditor->GetSelectionStart(), text.length());
m_pEditor->RefreshSelectionPos();
}
}
Expand Down Expand Up @@ -326,6 +328,8 @@ void JsonViewDlg::ValidateJson()

ReportError(res);
}

DrawJsonTree();
}

void JsonViewDlg::DrawJsonTree()
Expand Down Expand Up @@ -379,6 +383,16 @@ void JsonViewDlg::DrawJsonTree()
EnableControls(ctrls, true);
}

void JsonViewDlg::ReDrawJsonTree(bool bForce)
{
const bool bIsVisible = isCreated() && isVisible();
const bool bReDraw = bForce || bIsVisible;
if (bReDraw)
{
DrawJsonTree();
}
}

void JsonViewDlg::HighlightAsJson(bool bForcefully) const
{
bool setJsonLang = bForcefully || m_pSetting->bUseJsonHighlight;
Expand All @@ -390,10 +404,11 @@ auto JsonViewDlg::PopulateTreeUsingSax(HTREEITEM tree_root, const std::string& j
{
std::optional<std::wstring> retVal = std::nullopt;

RapidJsonHandler handler(this, tree_root);
auto pTS = std::make_shared<TrackingStream>(jsonText);
RapidJsonHandler handler(this, tree_root, pTS);
rapidjson::StringBuffer sb;

Result res = JsonHandler(m_pSetting->parseOptions).ParseJson<flgBaseReader>(jsonText, sb, handler);
Result res = JsonHandler(m_pSetting->parseOptions).ParseJson<flgBaseReader>(jsonText, sb, handler, pTS);
if (!res.success)
{
if (CheckForTokenUndefined(JsonViewDlg::eMethod::ParseJson, jsonText, res, tree_root))
Expand Down Expand Up @@ -429,6 +444,13 @@ HTREEITEM JsonViewDlg::InsertToTree(HTREEITEM parent, const std::string& text)
return m_hTreeView->InsertNode(wText, NULL, parent);
}

HTREEITEM JsonViewDlg::InsertToTree(HTREEITEM parent, const std::string& text, const Position& pos)
{
auto wText = StringHelper::ToWstring(text, CP_UTF8);
auto lparam = new Position(pos);
return m_hTreeView->InsertNode(wText, reinterpret_cast<LPARAM>(lparam), parent);
}

void JsonViewDlg::AppendNodeCount(HTREEITEM node, unsigned elementCount, bool bArray)
{
if (!node)
Expand All @@ -450,6 +472,16 @@ void JsonViewDlg::UpdateNodePath(HTREEITEM htiNode)
CUtility::SetEditCtrlText(::GetDlgItem(_hSelf, IDC_EDT_NODEPATH), nodePath);
}

void JsonViewDlg::GoToLine(size_t nLineToGo)
{
m_pEditor->GoToLine(nLineToGo);
}

void JsonViewDlg::GoToPosition(size_t nLineToGo, size_t nPos)
{
m_pEditor->GoToPosition(nLineToGo, nPos);
}

void JsonViewDlg::SearchInTree()
{
std::wstring itemToSearch = CUtility::GetEditCtrlText(::GetDlgItem(_hSelf, IDC_EDT_SEARCH));
Expand Down Expand Up @@ -878,6 +910,24 @@ void JsonViewDlg::HandleTreeEvents(LPARAM lParam)
if (hItem && (pnmtv->action == TVC_BYMOUSE || pnmtv->action == TVC_BYKEYBOARD))
{
UpdateNodePath(hItem);

auto pPosition = m_hTreeView->GetNodePosition(hItem);
if (pPosition != nullptr)
{
GoToLine(pPosition->nLine);
}
}
}
break;

case NM_DBLCLK:
{
HTREEITEM hItem = m_hTreeView->GetSelection();

auto pPosition = m_hTreeView->GetNodePosition(hItem);
if (pPosition != nullptr)
{
GoToPosition(pPosition->nLine, pPosition->nColumn);
}
}
break;
Expand Down
5 changes: 5 additions & 0 deletions src/NppJsonViewer/JsonViewDlg.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "TreeViewCtrl.h"
#include "ScintillaEditor.h"
#include "JsonHandler.h"
#include "JsonNode.h"


class JsonViewDlg : public DockingDlgInterface
Expand Down Expand Up @@ -44,16 +45,20 @@ class JsonViewDlg : public DockingDlgInterface
void UpdateTitle();

HTREEITEM InsertToTree(HTREEITEM parent, const std::string& text);
HTREEITEM InsertToTree(HTREEITEM parent, const std::string& text, const Position& pos);
void AppendNodeCount(HTREEITEM node, unsigned elementCount, bool bArray);

private:
void DrawJsonTree();
void ReDrawJsonTree(bool bForce = false);
void HighlightAsJson(bool bForcefully = false) const;
auto PopulateTreeUsingSax(HTREEITEM tree_root, const std::string& jsonText) -> std::optional<std::wstring>;

void ValidateJson();

void UpdateNodePath(HTREEITEM htiNode);
void GoToLine(size_t nLineToGo);
void GoToPosition(size_t nLineToGo, size_t nPos);

void SearchInTree();

Expand Down
1 change: 1 addition & 0 deletions src/NppJsonViewer/NPPJSONViewer.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@
<ClInclude Include="SettingsDlg.h" />
<ClInclude Include="ShortcutCommand.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="TrackingStream.h" />
<ClInclude Include="TreeViewCtrl.h" />
</ItemGroup>
<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions src/NppJsonViewer/NPPJSONViewer.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@
<ClInclude Include="..\..\external\npp\Window.h">
<Filter>ThirdParty\npp</Filter>
</ClInclude>
<ClInclude Include="TrackingStream.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="resource.rc">
Expand Down
28 changes: 15 additions & 13 deletions src/NppJsonViewer/RapidJsonHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ bool RapidJsonHandler::String(const Ch* str, unsigned /*length*/, bool /*copy*/)

bool RapidJsonHandler::Key(const Ch* str, unsigned /*length*/, bool /*copy*/)
{
m_strLastKey = str;
m_jsonLastKey.strKey = str;
m_jsonLastKey.pos.nLine = m_pTS->getLine();
m_jsonLastKey.pos.nColumn = m_pTS->getColumn();
return true;
}

Expand All @@ -101,13 +103,13 @@ bool RapidJsonHandler::StartObject()
parent = m_NodeStack.top();
}

if (!m_strLastKey.empty() || parent->node.type == JsonNodeType::ARRAY)
if (!m_jsonLastKey.strKey.empty() || parent->node.type == JsonNodeType::ARRAY)
{
HTREEITEM newNode = nullptr;
if (parent->node.type != JsonNodeType::ARRAY)
{
newNode = m_dlg->InsertToTree(parent->subRoot, m_strLastKey);
m_strLastKey.clear();
newNode = m_dlg->InsertToTree(parent->subRoot, m_jsonLastKey.strKey, m_jsonLastKey.pos);
m_jsonLastKey.clear();
}
else
{
Expand Down Expand Up @@ -150,13 +152,13 @@ bool RapidJsonHandler::StartArray()
parent = m_NodeStack.top();
}

if (!m_strLastKey.empty() || parent->node.type == JsonNodeType::ARRAY)
if (!m_jsonLastKey.strKey.empty() || parent->node.type == JsonNodeType::ARRAY)
{
HTREEITEM newNode;
if (parent->node.type != JsonNodeType::ARRAY)
{
newNode = m_dlg->InsertToTree(parent->subRoot, m_strLastKey);
m_strLastKey.clear();
newNode = m_dlg->InsertToTree(parent->subRoot, m_jsonLastKey.strKey, m_jsonLastKey.pos);
m_jsonLastKey.clear();
}
else
{
Expand Down Expand Up @@ -188,22 +190,22 @@ void RapidJsonHandler::InsertToTree(TreeNode* node, const char* const str, bool

if (node->node.type != JsonNodeType::ARRAY)
{
node->node.key = m_strLastKey;
node->node.key = m_jsonLastKey;
node->node.value = str;
m_strLastKey.clear();
m_jsonLastKey.clear();
}
else
{
node->node.key = "[" + std::to_string(node->counter) + "]";
node->node.value = str;
node->node.key.strKey = "[" + std::to_string(node->counter) + "]";
node->node.value = str;
node->counter++;
}

// Insert item to tree
if (bQuote)
m_dlg->InsertToTree(node->subRoot, node->node.key + " : \"" + node->node.value + "\"");
m_dlg->InsertToTree(node->subRoot, node->node.key.strKey + " : \"" + node->node.value + "\"", node->node.key.pos);
else
m_dlg->InsertToTree(node->subRoot, node->node.key + " : " + node->node.value);
m_dlg->InsertToTree(node->subRoot, node->node.key.strKey + " : " + node->node.value, node->node.key.pos);
}

void RapidJsonHandler::AppendNodeCount(unsigned elementCount, bool bArray)
Expand Down
Loading

0 comments on commit ed7909c

Please sign in to comment.