diff --git a/src/NppJsonViewer/Define.h b/src/NppJsonViewer/Define.h index a79064c..c7fa177 100644 --- a/src/NppJsonViewer/Define.h +++ b/src/NppJsonViewer/Define.h @@ -42,10 +42,11 @@ const TCHAR JSON_ERROR_TITLE[] = TEXT("JSON Viewer: Error"); const TCHAR JSON_WARNING_TITLE[] = TEXT("JSON Viewer: Warning"); const TCHAR JSON_INFO_TITLE[] = TEXT("JSON Viewer: Information"); -const TCHAR JSON_ERR_PARSE[] = TEXT("Cannot parse JSON. Please select a JSON string."); -const TCHAR JSON_ERR_VALIDATE[] = TEXT("There was an error while parsing JSON. Refer to the current selection for possible problematic area."); -const TCHAR JSON_ERR_VALIDATE_SUCCESS[] = TEXT("JSON looks good. No errors found while validating it."); -const TCHAR JSON_ERR_SAVE_SETTING[] = TEXT("Failed to save the settings. Please try again."); +const TCHAR JSON_ERR_PARSE[] = TEXT("Unable to parse JSON. Please ensure a valid JSON string is selected."); +const TCHAR JSON_ERR_VALIDATE[] = TEXT("An error occurred while parsing the JSON. Check the current selection for the potential issue."); +const TCHAR JSON_ERR_VALIDATE_SUCCESS[] = TEXT("The JSON appears valid. No errors were found during validation."); +const TCHAR JSON_ERR_SAVE_SETTING[] = TEXT("Could not save the settings. Please try again."); +const TCHAR JSON_ERR_MULTI_SELECTION[] = TEXT("Multiline selection is not currently supported in Json Viewer."); const TCHAR STR_VERSION[] = TEXT("Version: "); const TCHAR STR_COPY[] = TEXT("Copy"); diff --git a/src/NppJsonViewer/JsonViewDlg.cpp b/src/NppJsonViewer/JsonViewDlg.cpp index 2049cad..3513b6b 100644 --- a/src/NppJsonViewer/JsonViewDlg.cpp +++ b/src/NppJsonViewer/JsonViewDlg.cpp @@ -73,10 +73,19 @@ void JsonViewDlg::ShowDlg(bool bShow) void JsonViewDlg::FormatJson() { - const auto selectedText = m_pEditor->GetJsonText(); + const auto selectedData = m_pEditor->GetJsonText(); + const auto selectedText = IsSelectionValidJson(selectedData); + + if (!selectedText.has_value() || selectedText.value().empty()) + { + const std::wstring msg = IsMultiSelection(selectedData) ? JSON_ERR_MULTI_SELECTION : JSON_ERR_PARSE; + ShowMessage(JSON_INFO_TITLE, msg, MB_OK | MB_ICONINFORMATION); + return; + } + auto [le, lf, indentChar, indentLen] = GetFormatSetting(); - Result res = JsonHandler(m_pSetting->parseOptions).FormatJson(selectedText, le, lf, indentChar, indentLen); + Result res = JsonHandler(m_pSetting->parseOptions).FormatJson(selectedText.value(), le, lf, indentChar, indentLen); if (res.success) { @@ -85,7 +94,7 @@ void JsonViewDlg::FormatJson() } else { - if (CheckForTokenUndefined(JsonViewDlg::eMethod::FormatJson, selectedText, res, NULL)) + if (CheckForTokenUndefined(JsonViewDlg::eMethod::FormatJson, selectedText.value(), res, NULL)) return; ReportError(res); @@ -94,10 +103,17 @@ void JsonViewDlg::FormatJson() void JsonViewDlg::CompressJson() { - // Get the current scintilla - const auto selectedText = m_pEditor->GetJsonText(); + const auto selectedData = m_pEditor->GetJsonText(); + const auto selectedText = IsSelectionValidJson(selectedData); - Result res = JsonHandler(m_pSetting->parseOptions).GetCompressedJson(selectedText); + if (!selectedText.has_value() || selectedText.value().empty()) + { + const std::wstring msg = IsMultiSelection(selectedData) ? JSON_ERR_MULTI_SELECTION : JSON_ERR_PARSE; + ShowMessage(JSON_INFO_TITLE, msg, MB_OK | MB_ICONINFORMATION); + return; + } + + Result res = JsonHandler(m_pSetting->parseOptions).GetCompressedJson(selectedText.value()); if (res.success) { @@ -106,7 +122,7 @@ void JsonViewDlg::CompressJson() } else { - if (CheckForTokenUndefined(JsonViewDlg::eMethod::GetCompressedJson, selectedText, res, NULL)) + if (CheckForTokenUndefined(JsonViewDlg::eMethod::GetCompressedJson, selectedText.value(), res, NULL)) return; ReportError(res); @@ -115,10 +131,19 @@ void JsonViewDlg::CompressJson() void JsonViewDlg::SortJsonByKey() { - const auto selectedText = m_pEditor->GetJsonText(); + const auto selectedData = m_pEditor->GetJsonText(); + const auto selectedText = IsSelectionValidJson(selectedData); + + if (!selectedText.has_value() || selectedText.value().empty()) + { + const std::wstring msg = IsMultiSelection(selectedData) ? JSON_ERR_MULTI_SELECTION : JSON_ERR_PARSE; + ShowMessage(JSON_INFO_TITLE, msg, MB_OK | MB_ICONINFORMATION); + return; + } + auto [le, lf, indentChar, indentLen] = GetFormatSetting(); - Result res = JsonHandler(m_pSetting->parseOptions).SortJsonByKey(selectedText, le, lf, indentChar, indentLen); + Result res = JsonHandler(m_pSetting->parseOptions).SortJsonByKey(selectedText.value(), le, lf, indentChar, indentLen); if (res.success) { @@ -127,7 +152,7 @@ void JsonViewDlg::SortJsonByKey() } else { - if (CheckForTokenUndefined(JsonViewDlg::eMethod::SortJsonByKey, selectedText, res, NULL)) + if (CheckForTokenUndefined(JsonViewDlg::eMethod::SortJsonByKey, selectedText.value(), res, NULL)) return; ReportError(res); @@ -199,6 +224,52 @@ bool JsonViewDlg::CheckForTokenUndefined(eMethod method, std::string selectedTex return false; } +bool JsonViewDlg::IsMultiSelection(const ScintillaData &scintillaData) const +{ + std::string text; + ScintillaCode code = ScintillaCode::Unknown; + + ProcessScintillaData(scintillaData, text, code); + + bool bRetVal = code == ScintillaCode::MultiLineSelection ? true : false; + return bRetVal; +} + +auto JsonViewDlg::IsSelectionValidJson(const ScintillaData &scintillaData) const -> std::optional +{ + std::string text; + ScintillaCode code = ScintillaCode::Unknown; + + ProcessScintillaData(scintillaData, text, code); + + if (code == ScintillaCode::Success) + return text; + + return std::nullopt; +} + +void JsonViewDlg::ProcessScintillaData(const ScintillaData &scintillaData, std::string &text, ScintillaCode &code) const +{ + text.clear(); + code = ScintillaCode::Unknown; + + std::visit( + [&text, &code](auto &&arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + text = arg; + code = ScintillaCode::Success; + } + else if constexpr (std::is_same_v) + { + code = arg; + } + }, + scintillaData); +} + void JsonViewDlg::HandleTabActivated() { const bool bIsVisible = isCreated() && isVisible(); @@ -223,10 +294,17 @@ void JsonViewDlg::HandleTabActivated() void JsonViewDlg::ValidateJson() { - // Get the current scintilla - const auto selectedText = m_pEditor->GetJsonText(); + const auto selectedData = m_pEditor->GetJsonText(); + const auto selectedText = IsSelectionValidJson(selectedData); + + if (!selectedText.has_value() || selectedText.value().empty()) + { + const std::wstring msg = IsMultiSelection(selectedData) ? JSON_ERR_MULTI_SELECTION : JSON_ERR_PARSE; + ShowMessage(JSON_INFO_TITLE, msg, MB_OK | MB_ICONINFORMATION); + return; + } - Result res = JsonHandler(m_pSetting->parseOptions).ValidateJson(selectedText); + Result res = JsonHandler(m_pSetting->parseOptions).ValidateJson(selectedText.value()); if (res.success) { @@ -234,7 +312,7 @@ void JsonViewDlg::ValidateJson() } else { - if (CheckForTokenUndefined(JsonViewDlg::eMethod::ValidateJson, selectedText, res, NULL)) + if (CheckForTokenUndefined(JsonViewDlg::eMethod::ValidateJson, selectedText.value(), res, NULL)) { ShowMessage(JSON_INFO_TITLE, JSON_ERR_VALIDATE_SUCCESS, MB_OK | MB_ICONINFORMATION); return; @@ -255,15 +333,21 @@ void JsonViewDlg::DrawJsonTree() // Refresh the view m_pEditor->RefreshViewHandle(); - const std::string txtForParsing = m_pEditor->GetJsonText(); + const auto selectedData = m_pEditor->GetJsonText(); + const auto selectedText = IsSelectionValidJson(selectedData); - if (txtForParsing.empty()) + if (!selectedText.has_value() || selectedText.value().empty()) { m_hTreeView->InsertNode(JSON_ERR_PARSE, NULL, rootNode); + + if (IsMultiSelection(selectedData)) + { + ShowMessage(JSON_INFO_TITLE, JSON_ERR_MULTI_SELECTION, MB_OK | MB_ICONINFORMATION); + } } else { - auto res = PopulateTreeUsingSax(rootNode, txtForParsing); + auto res = PopulateTreeUsingSax(rootNode, selectedText.value()); if (res.has_value()) { // This is the case when Notepad++ has JsonViewer Window opened for previous instance diff --git a/src/NppJsonViewer/JsonViewDlg.h b/src/NppJsonViewer/JsonViewDlg.h index 5f8fcd3..c21c129 100644 --- a/src/NppJsonViewer/JsonViewDlg.h +++ b/src/NppJsonViewer/JsonViewDlg.h @@ -84,6 +84,10 @@ class JsonViewDlg : public DockingDlgInterface bool CheckForTokenUndefined(eMethod method, std::string selectedText, Result &res, HTREEITEM tree_root); + bool IsMultiSelection(const ScintillaData &scintillaData) const; + auto IsSelectionValidJson(const ScintillaData &scintillaData) const -> std::optional; + void ProcessScintillaData(const ScintillaData &scintillaData, std::string &text, ScintillaCode &code) const; + protected: virtual INT_PTR CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) override; diff --git a/src/NppJsonViewer/ScintillaEditor.cpp b/src/NppJsonViewer/ScintillaEditor.cpp index c0502bc..141d299 100644 --- a/src/NppJsonViewer/ScintillaEditor.cpp +++ b/src/NppJsonViewer/ScintillaEditor.cpp @@ -17,10 +17,15 @@ void ScintillaEditor::RefreshViewHandle() m_hScintilla = (which == 0) ? m_NppData._scintillaMainHandle : m_NppData._scintillaSecondHandle; } -auto ScintillaEditor::GetJsonText() -> std::string +auto ScintillaEditor::GetJsonText() -> ScintillaData { if (!m_hScintilla) - return std::string(); + return ScintillaCode::NotInitialized; + + // Multi selection is not supported + size_t nSelections = ::SendMessage(m_hScintilla, SCI_GETSELECTIONS, 0, 0); + if (nSelections > 1) + return ScintillaCode::MultiLineSelection; // Adjust the selection position RefreshSelectionPos(); diff --git a/src/NppJsonViewer/ScintillaEditor.h b/src/NppJsonViewer/ScintillaEditor.h index ac800bd..da60c80 100644 --- a/src/NppJsonViewer/ScintillaEditor.h +++ b/src/NppJsonViewer/ScintillaEditor.h @@ -2,6 +2,18 @@ #include "Define.h" #include #include +#include + +enum class ScintillaCode : short +{ + Unknown, + Success, + NotInitialized, + NoSelection, + MultiLineSelection +}; + +using ScintillaData = std::variant; class ScintillaEditor { @@ -10,7 +22,7 @@ class ScintillaEditor ~ScintillaEditor() = default; void RefreshViewHandle(); - auto GetJsonText() -> std::string; + auto GetJsonText() -> ScintillaData; void SetLangAsJson() const; bool IsJsonFile() const; auto GetCurrentFileName() const -> std::wstring;