From bd7255477ec6a56d96487c8bb84c87fe345fc254 Mon Sep 17 00:00:00 2001 From: SinghRajenM Date: Sat, 19 Oct 2024 14:59:16 +0530 Subject: [PATCH 1/3] Explore navigation on click --- src/NppJsonViewer/JsonHandler.h | 24 ++++-- src/NppJsonViewer/JsonNode.h | 25 +++++- src/NppJsonViewer/JsonViewDlg.cpp | 70 ++++++++++++--- src/NppJsonViewer/JsonViewDlg.h | 4 + src/NppJsonViewer/NPPJSONViewer.vcxproj | 1 + .../NPPJSONViewer.vcxproj.filters | 3 + src/NppJsonViewer/RapidJsonHandler.cpp | 28 +++--- src/NppJsonViewer/RapidJsonHandler.h | 15 ++-- src/NppJsonViewer/ScintillaEditor.cpp | 12 +++ src/NppJsonViewer/ScintillaEditor.h | 3 + src/NppJsonViewer/TrackingStream.h | 86 +++++++++++++++++++ src/NppJsonViewer/TreeViewCtrl.cpp | 53 +++++++++++- src/NppJsonViewer/TreeViewCtrl.h | 4 + 13 files changed, 286 insertions(+), 42 deletions(-) create mode 100644 src/NppJsonViewer/TrackingStream.h diff --git a/src/NppJsonViewer/JsonHandler.h b/src/NppJsonViewer/JsonHandler.h index ef3b448..f7988a9 100644 --- a/src/NppJsonViewer/JsonHandler.h +++ b/src/NppJsonViewer/JsonHandler.h @@ -10,6 +10,7 @@ #include #include "Define.h" +#include "TrackingStream.h" namespace rj = rapidjson; @@ -42,7 +43,7 @@ class JsonHandler auto ValidateJson(const std::string& jsonText) -> const Result; template - 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; @@ -51,13 +52,18 @@ class JsonHandler }; template -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 pSS = nullptr; + if (!pTS) + { + pSS = std::make_shared(jsonText.c_str()); + } // TODO: Find some better way constexpr auto flgBase_comment = flgBase | rj::kParseCommentsFlag; @@ -66,22 +72,22 @@ inline auto JsonHandler::ParseJson(const std::string& jsonText, rj::StringBuffer if (m_parseOptions.bIgnoreComment && m_parseOptions.bIgnoreTrailingComma) { - success = reader.Parse(ss, handler) && sb.GetString(); + success = pTS ? reader.Parse(*pTS, handler) && sb.GetString() : reader.Parse(*pSS, handler) && sb.GetString(); } else if (!m_parseOptions.bIgnoreComment && m_parseOptions.bIgnoreTrailingComma) { - success = reader.Parse(ss, handler) && sb.GetString(); + success = pTS ? reader.Parse(*pTS, handler) && sb.GetString() : reader.Parse(*pSS, handler) && sb.GetString(); } else if (m_parseOptions.bIgnoreComment && !m_parseOptions.bIgnoreTrailingComma) { - success = reader.Parse(ss, handler) && sb.GetString(); + success = pTS ? reader.Parse(*pTS, handler) && sb.GetString() : reader.Parse(*pSS, handler) && sb.GetString(); } else if (!m_parseOptions.bIgnoreComment && !m_parseOptions.bIgnoreTrailingComma) { - success = reader.Parse(ss, handler) && sb.GetString(); + success = pTS ? reader.Parse(*pTS, handler) && sb.GetString() : reader.Parse(*pSS, handler) && sb.GetString(); } if (success) diff --git a/src/NppJsonViewer/JsonNode.h b/src/NppJsonViewer/JsonNode.h index a1e5d02..58f3c95 100644 --- a/src/NppJsonViewer/JsonNode.h +++ b/src/NppJsonViewer/JsonNode.h @@ -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; }; diff --git a/src/NppJsonViewer/JsonViewDlg.cpp b/src/NppJsonViewer/JsonViewDlg.cpp index 77d0627..089ffb5 100644 --- a/src/NppJsonViewer/JsonViewDlg.cpp +++ b/src/NppJsonViewer/JsonViewDlg.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "JsonViewDlg.h" #include "Define.h" #include "Utility.h" @@ -5,8 +8,7 @@ #include "RapidJsonHandler.h" #include "ScintillaEditor.h" #include "Profile.h" -#include -#include + constexpr int FILENAME_LEN_IN_TITLE = 16; @@ -171,14 +173,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 @@ -390,10 +386,11 @@ auto JsonViewDlg::PopulateTreeUsingSax(HTREEITEM tree_root, const std::string& j { std::optional retVal = std::nullopt; - RapidJsonHandler handler(this, tree_root); + auto pTS = std::make_shared(jsonText); + RapidJsonHandler handler(this, tree_root, pTS); rapidjson::StringBuffer sb; - Result res = JsonHandler(m_pSetting->parseOptions).ParseJson(jsonText, sb, handler); + Result res = JsonHandler(m_pSetting->parseOptions).ParseJson(jsonText, sb, handler, pTS); if (!res.success) { if (CheckForTokenUndefined(JsonViewDlg::eMethod::ParseJson, jsonText, res, tree_root)) @@ -429,6 +426,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), parent); +} + void JsonViewDlg::AppendNodeCount(HTREEITEM node, unsigned elementCount, bool bArray) { if (!node) @@ -450,6 +454,16 @@ void JsonViewDlg::UpdateNodePath(HTREEITEM htiNode) CUtility::SetEditCtrlText(::GetDlgItem(_hSelf, IDC_EDT_NODEPATH), nodePath); } +void JsonViewDlg::GoToLine(size_t nLineToGo) +{ + m_pEditor->GoToLine(0, nLineToGo); +} + +void JsonViewDlg::GoToPosition(size_t nLineToGo, size_t nPos) +{ + m_pEditor->GoToPosition(0, nLineToGo, nPos); +} + void JsonViewDlg::SearchInTree() { std::wstring itemToSearch = CUtility::GetEditCtrlText(::GetDlgItem(_hSelf, IDC_EDT_SEARCH)); @@ -869,6 +883,20 @@ void JsonViewDlg::HandleTreeEvents(LPARAM lParam) if (!lpnmh || lpnmh->idFrom != IDC_TREE) return; // Not click inside JsonTree + auto GetNodePosition = [this](HTREEITEM hItem) + { + Position* pPosition = nullptr; + if (hItem != nullptr) + { + LPARAM nodePos = m_hTreeView->GetNodePos(hItem); + if (nodePos != -1) + { + pPosition = reinterpret_cast(nodePos); + } + } + return pPosition; + }; + switch (lpnmh->code) { case TVN_SELCHANGED: @@ -878,6 +906,24 @@ void JsonViewDlg::HandleTreeEvents(LPARAM lParam) if (hItem && (pnmtv->action == TVC_BYMOUSE || pnmtv->action == TVC_BYKEYBOARD)) { UpdateNodePath(hItem); + + auto pPosition = GetNodePosition(hItem); + if (pPosition != nullptr) + { + GoToLine(pPosition->nLine - 1); // line index start with 0 in editor, hence -- + } + } + } + break; + + case NM_DBLCLK: + { + HTREEITEM hItem = m_hTreeView->GetSelection(); + + auto pPosition = GetNodePosition(hItem); + if (pPosition != nullptr) + { + GoToPosition(pPosition->nLine - 1, pPosition->nColumn); // line index start with 0 in editor, hence -- } } break; diff --git a/src/NppJsonViewer/JsonViewDlg.h b/src/NppJsonViewer/JsonViewDlg.h index 598ecf4..4b9ba85 100644 --- a/src/NppJsonViewer/JsonViewDlg.h +++ b/src/NppJsonViewer/JsonViewDlg.h @@ -11,6 +11,7 @@ #include "TreeViewCtrl.h" #include "ScintillaEditor.h" #include "JsonHandler.h" +#include "JsonNode.h" class JsonViewDlg : public DockingDlgInterface @@ -44,6 +45,7 @@ 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: @@ -54,6 +56,8 @@ class JsonViewDlg : public DockingDlgInterface void ValidateJson(); void UpdateNodePath(HTREEITEM htiNode); + void GoToLine(size_t nLineToGo); + void GoToPosition(size_t nLineToGo, size_t nPos); void SearchInTree(); diff --git a/src/NppJsonViewer/NPPJSONViewer.vcxproj b/src/NppJsonViewer/NPPJSONViewer.vcxproj index 1c485a7..9665dfa 100644 --- a/src/NppJsonViewer/NPPJSONViewer.vcxproj +++ b/src/NppJsonViewer/NPPJSONViewer.vcxproj @@ -222,6 +222,7 @@ + diff --git a/src/NppJsonViewer/NPPJSONViewer.vcxproj.filters b/src/NppJsonViewer/NPPJSONViewer.vcxproj.filters index 130d490..f7cdb05 100644 --- a/src/NppJsonViewer/NPPJSONViewer.vcxproj.filters +++ b/src/NppJsonViewer/NPPJSONViewer.vcxproj.filters @@ -128,6 +128,9 @@ ThirdParty\npp + + Header Files + diff --git a/src/NppJsonViewer/RapidJsonHandler.cpp b/src/NppJsonViewer/RapidJsonHandler.cpp index ae2f370..6265a68 100644 --- a/src/NppJsonViewer/RapidJsonHandler.cpp +++ b/src/NppJsonViewer/RapidJsonHandler.cpp @@ -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; } @@ -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 { @@ -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 { @@ -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) diff --git a/src/NppJsonViewer/RapidJsonHandler.h b/src/NppJsonViewer/RapidJsonHandler.h index 16d4f24..a912276 100644 --- a/src/NppJsonViewer/RapidJsonHandler.h +++ b/src/NppJsonViewer/RapidJsonHandler.h @@ -8,7 +8,7 @@ #include #include "JsonNode.h" - +#include "TrackingStream.h" class JsonViewDlg; @@ -19,17 +19,20 @@ struct TreeNode int counter {}; }; + class RapidJsonHandler : public rapidjson::BaseReaderHandler, RapidJsonHandler> { - std::string m_strLastKey; + JsonKey m_jsonLastKey {}; std::stack m_NodeStack; - JsonViewDlg* m_dlg = nullptr; - HTREEITEM m_treeRoot = nullptr; + TrackingStreamSharedPtr m_pTS; + JsonViewDlg* m_dlg = nullptr; + HTREEITEM m_treeRoot = nullptr; public: - RapidJsonHandler(JsonViewDlg* dlg, HTREEITEM treeRoot) - : m_dlg(dlg) + RapidJsonHandler(JsonViewDlg* dlg, HTREEITEM treeRoot, TrackingStreamSharedPtr pTS = nullptr) + : m_pTS(pTS ? pTS->GetShared() : nullptr) + , m_dlg(dlg) , m_treeRoot(treeRoot) { } diff --git a/src/NppJsonViewer/ScintillaEditor.cpp b/src/NppJsonViewer/ScintillaEditor.cpp index c0c5d25..6167a79 100644 --- a/src/NppJsonViewer/ScintillaEditor.cpp +++ b/src/NppJsonViewer/ScintillaEditor.cpp @@ -98,3 +98,15 @@ void ScintillaEditor::RefreshSelectionPos() if (m_nEndPos < m_nStartPos) std::swap(m_nStartPos, m_nEndPos); } + +void ScintillaEditor::GoToLine(size_t nStartLine, size_t nLineToGo) const +{ + ::SendMessage(m_hScintilla, SCI_GOTOLINE, nStartLine + nLineToGo, 0); +} + +void ScintillaEditor::GoToPosition(size_t nStartLine, size_t nLineToGo, size_t nColumnIndex) const +{ + size_t lineStartPos = SendMessage(m_hScintilla, SCI_POSITIONFROMLINE, nStartLine + nLineToGo, 0); + size_t targetPos = lineStartPos + nColumnIndex; + ::SendMessage(m_hScintilla, SCI_GOTOPOS, targetPos, 0); +} diff --git a/src/NppJsonViewer/ScintillaEditor.h b/src/NppJsonViewer/ScintillaEditor.h index 6b3b675..cfef096 100644 --- a/src/NppJsonViewer/ScintillaEditor.h +++ b/src/NppJsonViewer/ScintillaEditor.h @@ -44,6 +44,9 @@ class ScintillaEditor void RefreshSelectionPos(); + void GoToLine(size_t nStartLine, size_t nLineToGo) const; + void GoToPosition(size_t nStartLine, size_t nLineToGo, size_t nColumnIndex) const; + private: NppData m_NppData = {}; HWND m_hScintilla = nullptr; diff --git a/src/NppJsonViewer/TrackingStream.h b/src/NppJsonViewer/TrackingStream.h new file mode 100644 index 0000000..43c3172 --- /dev/null +++ b/src/NppJsonViewer/TrackingStream.h @@ -0,0 +1,86 @@ +#pragma once + +#include +#include + +#include + + +class TrackingStream : public std::enable_shared_from_this +{ +private: + char m_chPrevChar {}; // Store previous character for handling column postion + size_t m_nLine {}; + size_t m_nColumn {}; + rapidjson::StringStream m_ss; + +public: + using Ch = char; // Define Ch to conform to RapidJSON's expectations + + TrackingStream(const std::string& jsonText) + : m_ss(jsonText.c_str()) + , m_nLine(1) + , m_nColumn(1) + , m_chPrevChar('\0') + { + } + + std::shared_ptr GetShared() + { + return shared_from_this(); + } + + inline size_t getLine() const + { + return m_nLine; + } + + inline size_t getColumn() const + { + return m_nColumn; + } + + // Read the next character and update line/column numbers + Ch Take() + { + Ch ch = m_ss.Take(); + if (ch == '\n') + { + ++m_nLine; + m_nColumn = 1; + } + else + { + ++m_nColumn; + } + m_chPrevChar = ch; + return ch; + } + + Ch Peek() const + { + return m_ss.Peek(); + } + + size_t Tell() const + { + return m_ss.Tell(); + } + + Ch* PutBegin() + { + return m_ss.PutBegin(); + } + + size_t PutEnd(Ch* pCh) + { + return m_ss.PutEnd(pCh); + } + + void Put(Ch ch) + { + m_ss.Put(ch); + } +}; + +using TrackingStreamSharedPtr = std::shared_ptr; diff --git a/src/NppJsonViewer/TreeViewCtrl.cpp b/src/NppJsonViewer/TreeViewCtrl.cpp index b98698b..ca63a54 100644 --- a/src/NppJsonViewer/TreeViewCtrl.cpp +++ b/src/NppJsonViewer/TreeViewCtrl.cpp @@ -13,7 +13,8 @@ void TreeViewCtrl::OnInit(HWND hParent) auto TreeViewCtrl::InitTree() -> HTREEITEM { if (GetNodeCount() > 0) - TreeView_DeleteAllItems(m_hTree); + DeleteAllNodes(); + m_nMaxNodeTextLength = 0; return InsertNode(JSON_ROOT, -1, TVI_ROOT); @@ -199,6 +200,17 @@ auto TreeViewCtrl::GetNodeName(HTREEITEM hti, bool removeTrailingCount) const -> return retVal; } +auto TreeViewCtrl::GetNodePos(HTREEITEM hti) const -> LPARAM +{ + TVITEM tvItem {}; + tvItem.hItem = hti; + tvItem.mask = TVIF_PARAM; + + if (SendMessage(m_hTree, TVM_GETITEM, 0, reinterpret_cast(&tvItem))) + return tvItem.lParam; + return -1; +} + auto TreeViewCtrl::GetNodeKey(HTREEITEM hti) const -> std::wstring { std::wstring retVal = GetNodeName(hti, true); @@ -339,3 +351,42 @@ bool TreeViewCtrl::SetTVItem(TVITEM* tvi) const { return TreeView_SetItem(m_hTree, tvi) ? true : false; } + +void TreeViewCtrl::FreeNodeData(HTREEITEM hItem) +{ + if (hItem == nullptr) + return; + + TVITEM tvi {}; + tvi.hItem = hItem; + tvi.mask = TVIF_PARAM; + + if (SendDlgItemMessage(m_hParent, IDC_TREE, TVM_GETITEM, 0, reinterpret_cast(&tvi))) + { + /*JsonLastKey *pLastKey = reinterpret_cast(tvi.lParam); + if (pLastKey) + { + delete pLastKey; + pLastKey = nullptr; + }*/ + } + + HTREEITEM hChild = TreeView_GetChild(m_hTree, hItem); + while (hChild != nullptr) + { + FreeNodeData(hChild); + hChild = TreeView_GetNextSibling(m_hTree, hChild); + } +} + +void TreeViewCtrl::DeleteAllNodes() +{ + HTREEITEM hRoot = GetRoot(); + + if (hRoot != nullptr) + { + FreeNodeData(hRoot); + } + + TreeView_DeleteAllItems(m_hTree); +} diff --git a/src/NppJsonViewer/TreeViewCtrl.h b/src/NppJsonViewer/TreeViewCtrl.h index 087b0df..6be0a3b 100644 --- a/src/NppJsonViewer/TreeViewCtrl.h +++ b/src/NppJsonViewer/TreeViewCtrl.h @@ -52,6 +52,7 @@ class TreeViewCtrl HTREEITEM NextItem(HTREEITEM htiCurrent, HTREEITEM htiNextRoot) const; auto GetNodeName(HTREEITEM hti, bool removeTrailingCount) const -> std::wstring; + auto GetNodePos(HTREEITEM hti) const -> LPARAM; auto GetNodeKey(HTREEITEM hti) const -> std::wstring; auto GetNodeValue(HTREEITEM hti) const -> std::wstring; auto GetNodePath(HTREEITEM hti) const -> std::wstring; @@ -63,4 +64,7 @@ class TreeViewCtrl bool GetTVItem(HTREEITEM hti, TVITEM* tvi) const; bool SetTVItem(TVITEM* tvi) const; + + void FreeNodeData(HTREEITEM hItem); + void DeleteAllNodes(); }; From 0008b20fc561addf8301baa2d951e25244c69a4e Mon Sep 17 00:00:00 2001 From: SinghRajenM Date: Sat, 19 Oct 2024 21:29:16 +0530 Subject: [PATCH 2/3] Re draw tree view on compress/format/sort validate etc. --- src/NppJsonViewer/JsonViewDlg.cpp | 28 ++++++++++++++++++++++----- src/NppJsonViewer/JsonViewDlg.h | 1 + src/NppJsonViewer/ScintillaEditor.cpp | 13 +++++++++---- src/NppJsonViewer/ScintillaEditor.h | 19 +++++++++++------- src/NppJsonViewer/TrackingStream.h | 4 ++-- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/NppJsonViewer/JsonViewDlg.cpp b/src/NppJsonViewer/JsonViewDlg.cpp index 089ffb5..c0be260 100644 --- a/src/NppJsonViewer/JsonViewDlg.cpp +++ b/src/NppJsonViewer/JsonViewDlg.cpp @@ -102,6 +102,8 @@ void JsonViewDlg::FormatJson() ReportError(res); } + + ReDrawJsonTree(); } void JsonViewDlg::CompressJson() @@ -132,6 +134,8 @@ void JsonViewDlg::CompressJson() ReportError(res); } + + ReDrawJsonTree(); } void JsonViewDlg::SortJsonByKey() @@ -164,6 +168,8 @@ void JsonViewDlg::SortJsonByKey() ReportError(res); } + + ReDrawJsonTree(); } bool JsonViewDlg::CheckForTokenUndefined(eMethod method, std::string selectedText, Result& res, HTREEITEM tree_root) @@ -213,7 +219,7 @@ bool JsonViewDlg::CheckForTokenUndefined(eMethod method, std::string selectedTex else { m_pEditor->ReplaceSelection(text); - m_pEditor->MakeSelection(m_pEditor->GetSelectionStart(), static_cast(text.length())); + m_pEditor->MakeSelection(m_pEditor->GetSelectionStart(), text.length()); m_pEditor->RefreshSelectionPos(); } } @@ -322,6 +328,8 @@ void JsonViewDlg::ValidateJson() ReportError(res); } + + DrawJsonTree(); } void JsonViewDlg::DrawJsonTree() @@ -375,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; @@ -456,12 +474,12 @@ void JsonViewDlg::UpdateNodePath(HTREEITEM htiNode) void JsonViewDlg::GoToLine(size_t nLineToGo) { - m_pEditor->GoToLine(0, nLineToGo); + m_pEditor->GoToLine(nLineToGo); } void JsonViewDlg::GoToPosition(size_t nLineToGo, size_t nPos) { - m_pEditor->GoToPosition(0, nLineToGo, nPos); + m_pEditor->GoToPosition(nLineToGo, nPos); } void JsonViewDlg::SearchInTree() @@ -910,7 +928,7 @@ void JsonViewDlg::HandleTreeEvents(LPARAM lParam) auto pPosition = GetNodePosition(hItem); if (pPosition != nullptr) { - GoToLine(pPosition->nLine - 1); // line index start with 0 in editor, hence -- + GoToLine(pPosition->nLine); } } } @@ -923,7 +941,7 @@ void JsonViewDlg::HandleTreeEvents(LPARAM lParam) auto pPosition = GetNodePosition(hItem); if (pPosition != nullptr) { - GoToPosition(pPosition->nLine - 1, pPosition->nColumn); // line index start with 0 in editor, hence -- + GoToPosition(pPosition->nLine, pPosition->nColumn); } } break; diff --git a/src/NppJsonViewer/JsonViewDlg.h b/src/NppJsonViewer/JsonViewDlg.h index 4b9ba85..d3f745c 100644 --- a/src/NppJsonViewer/JsonViewDlg.h +++ b/src/NppJsonViewer/JsonViewDlg.h @@ -50,6 +50,7 @@ class JsonViewDlg : public DockingDlgInterface 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; diff --git a/src/NppJsonViewer/ScintillaEditor.cpp b/src/NppJsonViewer/ScintillaEditor.cpp index 6167a79..fda6652 100644 --- a/src/NppJsonViewer/ScintillaEditor.cpp +++ b/src/NppJsonViewer/ScintillaEditor.cpp @@ -69,6 +69,9 @@ auto ScintillaEditor::GetCurrentFileName() const -> std::wstring void ScintillaEditor::ReplaceSelection(const std::string& text) const { ::SendMessage(m_hScintilla, SCI_REPLACESEL, 0, reinterpret_cast(text.c_str())); + + // Restore the selection + MakeSelection(m_nStartPos, m_nStartPos + text.length()); } void ScintillaEditor::MakeSelection(size_t start, size_t end) const @@ -97,16 +100,18 @@ void ScintillaEditor::RefreshSelectionPos() if (m_nEndPos < m_nStartPos) std::swap(m_nStartPos, m_nEndPos); + + m_nStartLine = ::SendMessage(m_hScintilla, SCI_LINEFROMPOSITION, m_nStartPos, 0); } -void ScintillaEditor::GoToLine(size_t nStartLine, size_t nLineToGo) const +void ScintillaEditor::GoToLine(size_t nLineToGo) const { - ::SendMessage(m_hScintilla, SCI_GOTOLINE, nStartLine + nLineToGo, 0); + ::SendMessage(m_hScintilla, SCI_GOTOLINE, m_nStartLine + nLineToGo, 0); } -void ScintillaEditor::GoToPosition(size_t nStartLine, size_t nLineToGo, size_t nColumnIndex) const +void ScintillaEditor::GoToPosition(size_t nLineToGo, size_t nColumnIndex) const { - size_t lineStartPos = SendMessage(m_hScintilla, SCI_POSITIONFROMLINE, nStartLine + nLineToGo, 0); + size_t lineStartPos = SendMessage(m_hScintilla, SCI_POSITIONFROMLINE, m_nStartLine + nLineToGo, 0); size_t targetPos = lineStartPos + nColumnIndex; ::SendMessage(m_hScintilla, SCI_GOTOPOS, targetPos, 0); } diff --git a/src/NppJsonViewer/ScintillaEditor.h b/src/NppJsonViewer/ScintillaEditor.h index cfef096..a7747d3 100644 --- a/src/NppJsonViewer/ScintillaEditor.h +++ b/src/NppJsonViewer/ScintillaEditor.h @@ -29,28 +29,33 @@ class ScintillaEditor void ReplaceSelection(const std::string& text) const; - void MakeSelection(size_t start, size_t end) const; - auto GetSelectionStart() const -> size_t + void MakeSelection(size_t start, size_t end) const; + inline auto GetSelectionStart() const -> size_t { return m_nStartPos; } - auto GetSelectionEnd() const -> size_t + inline auto GetSelectionEnd() const -> size_t { return m_nEndPos; } + inline auto GetSelectionStartLine() const -> size_t + { + return m_nStartLine; + } auto GetEOL() const -> unsigned; auto GetIndent() const -> std::tuple; void RefreshSelectionPos(); - void GoToLine(size_t nStartLine, size_t nLineToGo) const; - void GoToPosition(size_t nStartLine, size_t nLineToGo, size_t nColumnIndex) const; + void GoToLine(size_t nLineToGo) const; + void GoToPosition(size_t nLineToGo, size_t nColumnIndex) const; private: NppData m_NppData = {}; HWND m_hScintilla = nullptr; - size_t m_nStartPos = 0; - size_t m_nEndPos = 0; + size_t m_nStartLine = 0; + size_t m_nStartPos = 0; + size_t m_nEndPos = 0; }; diff --git a/src/NppJsonViewer/TrackingStream.h b/src/NppJsonViewer/TrackingStream.h index 43c3172..51a84bb 100644 --- a/src/NppJsonViewer/TrackingStream.h +++ b/src/NppJsonViewer/TrackingStream.h @@ -19,8 +19,8 @@ class TrackingStream : public std::enable_shared_from_this TrackingStream(const std::string& jsonText) : m_ss(jsonText.c_str()) - , m_nLine(1) - , m_nColumn(1) + , m_nLine(0) + , m_nColumn(0) , m_chPrevChar('\0') { } From deea1c3edc8c89081c7527a39c3859848584e507 Mon Sep 17 00:00:00 2001 From: SinghRajenM Date: Sat, 19 Oct 2024 21:53:09 +0530 Subject: [PATCH 3/3] Fix memory leak --- src/NppJsonViewer/JsonViewDlg.cpp | 18 ++--------------- src/NppJsonViewer/TreeViewCtrl.cpp | 32 +++++++++++++++++++----------- src/NppJsonViewer/TreeViewCtrl.h | 7 ++++++- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/NppJsonViewer/JsonViewDlg.cpp b/src/NppJsonViewer/JsonViewDlg.cpp index c0be260..3387269 100644 --- a/src/NppJsonViewer/JsonViewDlg.cpp +++ b/src/NppJsonViewer/JsonViewDlg.cpp @@ -901,20 +901,6 @@ void JsonViewDlg::HandleTreeEvents(LPARAM lParam) if (!lpnmh || lpnmh->idFrom != IDC_TREE) return; // Not click inside JsonTree - auto GetNodePosition = [this](HTREEITEM hItem) - { - Position* pPosition = nullptr; - if (hItem != nullptr) - { - LPARAM nodePos = m_hTreeView->GetNodePos(hItem); - if (nodePos != -1) - { - pPosition = reinterpret_cast(nodePos); - } - } - return pPosition; - }; - switch (lpnmh->code) { case TVN_SELCHANGED: @@ -925,7 +911,7 @@ void JsonViewDlg::HandleTreeEvents(LPARAM lParam) { UpdateNodePath(hItem); - auto pPosition = GetNodePosition(hItem); + auto pPosition = m_hTreeView->GetNodePosition(hItem); if (pPosition != nullptr) { GoToLine(pPosition->nLine); @@ -938,7 +924,7 @@ void JsonViewDlg::HandleTreeEvents(LPARAM lParam) { HTREEITEM hItem = m_hTreeView->GetSelection(); - auto pPosition = GetNodePosition(hItem); + auto pPosition = m_hTreeView->GetNodePosition(hItem); if (pPosition != nullptr) { GoToPosition(pPosition->nLine, pPosition->nColumn); diff --git a/src/NppJsonViewer/TreeViewCtrl.cpp b/src/NppJsonViewer/TreeViewCtrl.cpp index ca63a54..844c685 100644 --- a/src/NppJsonViewer/TreeViewCtrl.cpp +++ b/src/NppJsonViewer/TreeViewCtrl.cpp @@ -1,7 +1,8 @@ +#include + #include "TreeViewCtrl.h" #include "Define.h" #include "resource.h" -#include void TreeViewCtrl::OnInit(HWND hParent) @@ -280,6 +281,20 @@ auto TreeViewCtrl::GetNodePath(HTREEITEM hti) const -> std::wstring return wstrJsonPath; } +auto TreeViewCtrl::GetNodePosition(HTREEITEM hti) const -> Position* +{ + Position* pPosition = nullptr; + if (hti != nullptr) + { + LPARAM nodePos = GetNodePos(hti); + if (nodePos != -1) + { + pPosition = reinterpret_cast(nodePos); + } + } + return pPosition; +} + HTREEITEM TreeViewCtrl::GetSelection() const { return TreeView_GetSelection(m_hTree); @@ -357,18 +372,11 @@ void TreeViewCtrl::FreeNodeData(HTREEITEM hItem) if (hItem == nullptr) return; - TVITEM tvi {}; - tvi.hItem = hItem; - tvi.mask = TVIF_PARAM; - - if (SendDlgItemMessage(m_hParent, IDC_TREE, TVM_GETITEM, 0, reinterpret_cast(&tvi))) + Position* pNodeKeyPos = GetNodePosition(hItem); + if (pNodeKeyPos) { - /*JsonLastKey *pLastKey = reinterpret_cast(tvi.lParam); - if (pLastKey) - { - delete pLastKey; - pLastKey = nullptr; - }*/ + delete pNodeKeyPos; + pNodeKeyPos = nullptr; } HTREEITEM hChild = TreeView_GetChild(m_hTree, hItem); diff --git a/src/NppJsonViewer/TreeViewCtrl.h b/src/NppJsonViewer/TreeViewCtrl.h index 6be0a3b..73dfb01 100644 --- a/src/NppJsonViewer/TreeViewCtrl.h +++ b/src/NppJsonViewer/TreeViewCtrl.h @@ -1,7 +1,11 @@ #pragma once + +#include + #include #include -#include + +#include "JsonNode.h" class TreeViewCtrl { @@ -56,6 +60,7 @@ class TreeViewCtrl auto GetNodeKey(HTREEITEM hti) const -> std::wstring; auto GetNodeValue(HTREEITEM hti) const -> std::wstring; auto GetNodePath(HTREEITEM hti) const -> std::wstring; + auto GetNodePosition(HTREEITEM hti) const -> Position*; private: void ExpandOrCollapse(HTREEITEM node, UINT_PTR code) const;