From d2494108c7583c7fb36935a3c7621aecf82050c6 Mon Sep 17 00:00:00 2001 From: molsonkiko <46202915+molsonkiko@users.noreply.github.com> Date: Tue, 10 Sep 2024 22:39:35 -0700 Subject: [PATCH] Fix bugs; rename tree view when file renamed ADD: * When a file is renamed, the name of a tree view associated with that file also changes to match the new name. FIX: * Fix minor bugs with how headers are formatted in the `s_csv` RemesPath function and JSON-to-CSV form * Fix bug where renaming a file subject to schema validation based on filename patterns would cause its tree view to be lost. * Fix bug where plugin actions (mainly RemesPath queries in regex mode) that set the text of the entire document to an empty string would not do anything. Those actions will now correctly remove all the text in the document. --- CHANGELOG.md | 5 + .../Forms/ErrorForm.Designer.cs | 15 ++- JsonToolsNppPlugin/Forms/ErrorForm.cs | 2 + .../Forms/TreeViewer.Designer.cs | 15 ++- JsonToolsNppPlugin/Forms/TreeViewer.cs | 50 ++++++--- .../JSONTools/JsonTabularize.cs | 95 ++++++++--------- .../JSONTools/RemesPathFunctions.cs | 26 ++++- JsonToolsNppPlugin/Main.cs | 26 ++--- .../PluginInfrastructure/Docking_h.cs | 2 +- .../PluginInfrastructure/ScintillaGateway.cs | 5 + JsonToolsNppPlugin/Properties/AssemblyInfo.cs | 4 +- .../Tests/JsonTabularizerTests.cs | 7 +- JsonToolsNppPlugin/Tests/RemesPathTests.cs | 13 ++- .../Tests/UserInterfaceTests.cs | 2 + docs/README.md | 2 +- most recent errors.txt | 100 +++++++++--------- 16 files changed, 226 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddb2fdd..f429a87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +1. When a file is renamed, the name of a [tree view](/docs/README.md#json-tools-overview) associated with that file also changes to match the new name. + ### Changed ### Fixed @@ -65,6 +67,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). 2. Fix issue where RemesPath incorrectly inferred the type of (a [function](/docs/RemesPath.md#functions) `fun` followed by [indexers](/docs/RemesPath.md#indexing-and-selecting-keys)) to be the return type of `fun`. For example, running the query `sum(dict(items(@)).a)` on the JSON `{"a": [1]}` now correctly returns `1.0`, but RemesPath *used to raise an error because it assumed that `dict(items(@)).a` had the same type as `dict(items(@))`* 3. Fix very rare crash bug when using the `Value to clipboard` option of the [tree node right-click context menu](/docs/README.md#get-info-about-tree-nodes). 4. Fix bug where some invalid JSON Lines documents (for example, `[1, \n2][3]`) would be accepted by the [JSON Lines parser](/docs/README.md#json-lines-documents) despite having elements that span multiple lines. +5. Fix minor bugs with how headers are formatted in [the `s_csv` RemesPath function](/docs/RemesPath.md#vectorized-functions) and [JSON-to-CSV form](/docs/README.md#json-to-csv). +6. Fix bug where renaming a file subject to [schema validation based on filename patterns](/docs/README.md#automatic-validation-of-json-against-json-schema) would cause its tree view to be lost. +7. Fix bug where plugin actions (mainly RemesPath queries in [regex mode](/docs/README.md#regex-search-form)) that set the text of the entire document to an empty string would not do anything. Those actions will now correctly remove all the text in the document. ## [8.1.0] - 2024-08-23 diff --git a/JsonToolsNppPlugin/Forms/ErrorForm.Designer.cs b/JsonToolsNppPlugin/Forms/ErrorForm.Designer.cs index 8afb177..729e5a2 100644 --- a/JsonToolsNppPlugin/Forms/ErrorForm.Designer.cs +++ b/JsonToolsNppPlugin/Forms/ErrorForm.Designer.cs @@ -1,4 +1,7 @@ -namespace JSON_Tools.Forms +using System.Runtime.InteropServices; +using System; + +namespace JSON_Tools.Forms { partial class ErrorForm { @@ -18,6 +21,16 @@ protected override void Dispose(bool disposing) NppFormHelper.UnregisterFormIfModeless(this, false); components.Dispose(); } + if (ptrTitleBuf != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptrTitleBuf); + ptrTitleBuf = IntPtr.Zero; + } + if (ptrNppTbData != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptrNppTbData); + ptrNppTbData = IntPtr.Zero; + } base.Dispose(disposing); } diff --git a/JsonToolsNppPlugin/Forms/ErrorForm.cs b/JsonToolsNppPlugin/Forms/ErrorForm.cs index 6ceb4c9..cd8f4c9 100644 --- a/JsonToolsNppPlugin/Forms/ErrorForm.cs +++ b/JsonToolsNppPlugin/Forms/ErrorForm.cs @@ -20,6 +20,8 @@ public partial class ErrorForm : Form public string fname; public List lints; private bool isRepopulatingErrorGrid; + public IntPtr ptrNppTbData = IntPtr.Zero; + public IntPtr ptrTitleBuf = IntPtr.Zero; public ErrorForm(string fname, List lints) { diff --git a/JsonToolsNppPlugin/Forms/TreeViewer.Designer.cs b/JsonToolsNppPlugin/Forms/TreeViewer.Designer.cs index 8f6e469..55a2af0 100644 --- a/JsonToolsNppPlugin/Forms/TreeViewer.Designer.cs +++ b/JsonToolsNppPlugin/Forms/TreeViewer.Designer.cs @@ -1,4 +1,7 @@ -namespace JSON_Tools.Forms +using System; +using System.Runtime.InteropServices; + +namespace JSON_Tools.Forms { partial class TreeViewer { @@ -24,6 +27,16 @@ protected override void Dispose(bool disposing) findReplaceForm.Dispose(); findReplaceForm = null; } + if (ptrTitleBuf != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptrTitleBuf); + ptrTitleBuf = IntPtr.Zero; + } + if (ptrNppTbData != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptrNppTbData); + ptrNppTbData = IntPtr.Zero; + } if (disposing && (components != null)) { NppFormHelper.UnregisterFormIfModeless(this, false); diff --git a/JsonToolsNppPlugin/Forms/TreeViewer.cs b/JsonToolsNppPlugin/Forms/TreeViewer.cs index 239f8bf..f101015 100644 --- a/JsonToolsNppPlugin/Forms/TreeViewer.cs +++ b/JsonToolsNppPlugin/Forms/TreeViewer.cs @@ -2,12 +2,14 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; using JSON_Tools.JSON_Tools; using JSON_Tools.Utils; using Kbg.NppPluginNET; +using Kbg.NppPluginNET.PluginInfrastructure; namespace JSON_Tools.Forms { @@ -23,6 +25,15 @@ public partial class TreeViewer : Form /// public string fname; + private int MAX_LEN_TITLE_BUFFER = 256; + + /// + /// a pointer to the buffer containing the name displayed at the top of this docking form + /// + public IntPtr ptrTitleBuf = IntPtr.Zero; + + public IntPtr ptrNppTbData = IntPtr.Zero; + /// /// Maps TreeNode.FullPath to the TreeNode's corresponding JNode /// @@ -1454,25 +1465,40 @@ private void DocumentTypeComboBox_SelectedIndexChanged(object sender, EventArgs } /// - /// Just the filename, no directory information.

- /// If no fname supplied, gets the relative filename for this TreeViewer's fname. + /// Change the fname attribute of this.

+ /// Also change the title of the UI element (the docking form that the user actually sees) ///
- public string RelativeFilename(string fname = null) + /// + public void Rename(string newFname, bool isFilename) { - if (fname == null) fname = this.fname; - string[] fnameSplit = fname.Split('\\'); - return fnameSplit[fnameSplit.Length - 1]; + fname = newFname; + SetTitleBuffer(newFname, isFilename); + Marshal.WriteIntPtr(ptrNppTbData, IntPtr.Size, ptrTitleBuf); + Win32.SendMessage(PluginBase.nppData._nppHandle, (uint)NppMsg.NPPM_DMMUPDATEDISPINFO, 0, Handle); } /// - /// Change the fname attribute of this.

- /// We would like to be able to change the title of the UI element as well, - /// but it seems pretty hard to do from C#. + /// sets this.ptrTitleBuf to a pointer to an unmanaged Unicode char array containing the title of this TreeViewer's docking form.

+ /// If isFilename, strips the directory name away from the beginning of title. ///
- /// - public void Rename(string newFname) + public IntPtr SetTitleBuffer(string title, bool isFilename) { - fname = newFname; + if (isFilename) + { + string[] fnameSplit = fname.Split('\\'); + title = fnameSplit[fnameSplit.Length - 1]; + } + string defaultNameFormat = "Json Tree View for {0}"; + string nameFormat = (Translator.TryGetTranslationAtPath(new string[] { "forms", "TreeViewer", "title" }, out JNode node) && node.value is string s && s.Contains("{0}")) ? s : defaultNameFormat; + string fullTitle = nameFormat.Replace("{0}", title); + int maxCharsTitleBuf = MAX_LEN_TITLE_BUFFER / Marshal.SystemDefaultCharSize - 1; + if (fullTitle.Length > maxCharsTitleBuf) + fullTitle = fullTitle.Substring(0, maxCharsTitleBuf - 3) + "..."; + if (ptrTitleBuf == IntPtr.Zero) + ptrTitleBuf = Marshal.AllocHGlobal(MAX_LEN_TITLE_BUFFER); + Marshal.Copy(new byte[MAX_LEN_TITLE_BUFFER], 0, ptrTitleBuf, MAX_LEN_TITLE_BUFFER); + Marshal.Copy(fullTitle.ToCharArray(), 0, ptrTitleBuf, fullTitle.Length); + return ptrTitleBuf; } } } diff --git a/JsonToolsNppPlugin/JSONTools/JsonTabularize.cs b/JsonToolsNppPlugin/JSONTools/JsonTabularize.cs index e594e93..65e0f60 100644 --- a/JsonToolsNppPlugin/JSONTools/JsonTabularize.cs +++ b/JsonToolsNppPlugin/JSONTools/JsonTabularize.cs @@ -136,8 +136,8 @@ public JsonFormat outputFormat } public JsonTabularizer(JsonTabularizerStrategy strategy = JsonTabularizerStrategy.DEFAULT) // , - // JsonFormat outputFormat = JsonFormat.REC) - // don't worry about outputFormat, because other output formats aren't supported + // JsonFormat outputFormat = JsonFormat.REC) + // don't worry about outputFormat, because other output formats aren't supported { this.strategy = strategy; //if ((outputFormat & JsonFormat.ANY_TABLE) != 0) _outputFormat = outputFormat; @@ -446,14 +446,14 @@ private void AnyTableToRecord(JNode obj, } notArrDict = ResolveHang(notArrDict, keySep); if (lenArr == 0) - { + { // A 0-length array should be dealt with by adding a single row with an empty value // for the array's parent key foreach (string k in arrDict.Keys) notArrDict[k] = new JNode("", Dtype.STR, 0); result.Add(new JObject(0, notArrDict)); return; - } + } for (int ii = 0; ii < lenArr; ii++) { Dictionary newrec = new Dictionary(restOfRow); @@ -650,7 +650,7 @@ private void BuildTableHelper_FULL_RECURSIVE(JNode obj, private void BuildTableHelper_STRINGIFY_ITERABLES(JNode obj, List result, string keySep = ".") { if (obj is JArray) - { + { foreach (JNode child in ((JArray)obj).children) { Dictionary row = new Dictionary(); @@ -724,8 +724,8 @@ private void BuildTableHelper_STRINGIFY_ITERABLES(JNode obj, List result, // are filled by empty strings if (ii >= v.Length) newrec[k] = new JNode("", Dtype.STR, 0); - else - { + else + { JNode subchild = v[ii]; if (subchild is JArray subarr) newrec[k] = new JNode(subarr.ToString(), Dtype.STR, 0); @@ -733,7 +733,7 @@ private void BuildTableHelper_STRINGIFY_ITERABLES(JNode obj, List result, newrec[k] = new JNode(subobj.ToString(), Dtype.STR, 0); else newrec[k] = subchild; - } + } } // now add in all the non-array values foreach (string k in notArrDict.Keys) @@ -795,17 +795,17 @@ public JArray BuildTable(JNode obj, Dictionary schema, string ke return new JArray(0, result); } - /// - /// If string s contains the delimiter, '\r', '\n', or a literal quote character, append (the string wrapped in quotes) to sb.

- /// If s contains literal quote character, it is escaped by doubling it up according to the CSV RFC 4180 (https://www.ietf.org/rfc/rfc4180.txt)

- /// Otherwise, append s to sb unchanged - ///
- /// CSV delimiter ('\x00' if not specified) - /// CSV quote char ('\x00' if not specified) - /// - public static void ApplyQuotesIfNeeded(StringBuilder sb, string s, char delim, char quote) + /// + /// If string s contains the delimiter, '\r', '\n', or a literal quote character, append (the string wrapped in quotes) to sb.

+ /// If s contains literal quote character, it is escaped by doubling it up according to the CSV RFC 4180 (https://www.ietf.org/rfc/rfc4180.txt)

+ /// Otherwise, append s to sb unchanged + ///
+ /// CSV delimiter ('\x00' if not specified) + /// CSV quote char ('\x00' if not specified) + /// + public static void ApplyQuotesIfNeeded(StringBuilder sb, string s, char delim, char quote) { - if (s.IndexOfAny(new char[] {delim, '\r', '\n', quote}) >= 0) + if (s.IndexOfAny(new char[] { delim, '\r', '\n', quote }) >= 0) { sb.Append(quote); for (int ii = 0; ii < s.Length; ii++) @@ -813,46 +813,46 @@ public static void ApplyQuotesIfNeeded(StringBuilder sb, string s, char delim, c char c = s[ii]; sb.Append(c); if (c == quote) - sb.Append(quote); + sb.Append(quote); } sb.Append(quote); } else sb.Append(s); } - /// - /// append the CSV (RFC 4180 adherent, using quote character = quote, delimiter = delim) representation of jnode's value to sb. - /// - /// CSV delimiter ('\x00' if not specified) - /// CSV quote char ('\x00' if not specified) - /// if true, represent true as "1" and false as "0". If false, represent them as "true" and "false" respectively - public static void CsvStringToSb(StringBuilder sb, JNode jnode, char delim, char quote, bool boolsAsInts) + /// + /// append the CSV (RFC 4180 adherent, using quote character = quote, delimiter = delim) representation of jnode's value to sb. + /// + /// CSV delimiter ('\x00' if not specified) + /// CSV quote char ('\x00' if not specified) + /// if true, represent true as "1" and false as "0". If false, represent them as "true" and "false" respectively + public static void CsvStringToSb(StringBuilder sb, JNode jnode, char delim, char quote, bool boolsAsInts) { string val; - switch (jnode.type) - { - case Dtype.STR: - val = (string)jnode.value; - break; // only apply quotes if internal delims, quotes, or newlines - //case Dtype.DATE: - // val = ((DateTime)jnode.value).ToString("yyyy-MM-dd"); - // break; - //case Dtype.DATETIME: - // val = ((DateTime)jnode.value).ToString("yyyy-MM-dd hh:mm:ss"); - // break; - case Dtype.NULL: - return; // nulls should be empty entries - case Dtype.BOOL: + switch (jnode.type) + { + case Dtype.STR: + val = (string)jnode.value; + break; // only apply quotes if internal delims, quotes, or newlines + //case Dtype.DATE: + // val = ((DateTime)jnode.value).ToString("yyyy-MM-dd"); + // break; + //case Dtype.DATETIME: + // val = ((DateTime)jnode.value).ToString("yyyy-MM-dd hh:mm:ss"); + // break; + case Dtype.NULL: + return; // nulls should be empty entries + case Dtype.BOOL: sb.Append((bool)jnode.value ? (boolsAsInts ? "1" : "true") : (boolsAsInts ? "0" : "false")); - return; - default: - val = jnode.ToString(); - break; - } + return; + default: + val = jnode.ToString(); + break; + } ApplyQuotesIfNeeded(sb, val, delim, quote); - } + } public string TableToCsv(JArray table, char delim = ',', char quote = '"', string newline = "\n", string[] header = null, bool boolsAsInts = false) { @@ -878,8 +878,7 @@ public string TableToCsv(JArray table, char delim = ',', char quote = '"', strin StringBuilder sb = new StringBuilder(); for (int ii = 0; ii < header.Length; ii++) { - string col = header[ii]; - ApplyQuotesIfNeeded(sb, JNode.StrToString(col, false), delim, quote); + ApplyQuotesIfNeeded(sb, header[ii], delim, quote); if (ii < header.Length - 1) sb.Append(delim); } sb.Append(newline); diff --git a/JsonToolsNppPlugin/JSONTools/RemesPathFunctions.cs b/JsonToolsNppPlugin/JSONTools/RemesPathFunctions.cs index 3d86b32..feff352 100644 --- a/JsonToolsNppPlugin/JSONTools/RemesPathFunctions.cs +++ b/JsonToolsNppPlugin/JSONTools/RemesPathFunctions.cs @@ -2735,6 +2735,24 @@ private static void CacheResultsOfRegexSearch(string input, Regex rex, HeaderHan regexSearchResultCache[(input, argsAsJArrayString)] = output; } + /// + /// Unquote a string that is quoted according to RFC 4180 conventions, where str is enclosed in quoteChars and each literal quoteChar is doubled.

+ /// If str is not wrapped in quoteChars, or if quoteChar is '\x00', return str. + /// EXAMPLES:

+ /// * UnquoteCsvQuotedString("|foo||bar|", '|', "|", "||") would return "foo|bar"

+ /// * UnquoteCsvQuotedString("^^^quz^", '^', "^", "^^") would return "^quz"

+ /// * UnquoteCsvQuotedString("bllo", '"', "\"", "\"\"") would return "bllo" (because it's not wrapped in quotes)

+ /// * UnquoteCsvQuotedString("^bllo^", '\x00', "\x00", "\x00\x00") would return "bllo" (because quoteChar is '\x00') + ///
+ /// unless quoteChar == '\x00', must be new string(quoteChar, 1) + /// unless quoteChar == '\x00', must be new string(quoteChar, 2) + private static string UnquoteCsvQuotedString(string str, char quoteChar, string quoteStr, string doubleQuoteStr) + { + if (quoteChar > 0 && str.Length > 0 && str[0] == quoteChar) + return str.Substring(1, str.Length - 2).Replace(doubleQuoteStr, quoteStr); + return str; + } + /// /// return an array of strings(if rex has 0 or 1 capture group(s)) or an array of arrays of strings (if there are multiple capture groups)

/// The arguments in args at index firstOptionalArgNum onward will be treated as the 0-based indices of capture groups to parse as numbers

@@ -2772,9 +2790,7 @@ JNode matchEvaluator(string mValue, bool tryParseAsNumber, int jnodePosition) parsed.value = parsedStr.Substring(1, parsedStr.Length - 2).Replace(doubleQuoteStr, quoteStr); return parsed; } - if (csvQuoteChar > 0 && mValue.Length > 0 && mValue[0] == csvQuoteChar) - return new JNode(mValue.Substring(1, mValue.Length - 2).Replace(doubleQuoteStr, quoteStr), jnodePosition); - return new JNode(mValue, jnodePosition); + return new JNode(UnquoteCsvQuotedString(mValue, csvQuoteChar, quoteStr, doubleQuoteStr), jnodePosition); } int minGroupNum = headerHandling == HeaderHandlingInCsv.INCLUDE_FULL_MATCH_AS_FIRST_ITEM ? 0 : 1; int nColumns = minGroupNum >= maxGroupNum ? 1 : maxGroupNum + 1 - minGroupNum; @@ -2828,7 +2844,7 @@ JNode matchEvaluator(string mValue, bool tryParseAsNumber, int jnodePosition) { if (headerHandling == HeaderHandlingInCsv.MAP_HEADER_TO_ROWS) { - header = new List { mValue }; + header = new List { UnquoteCsvQuotedString(mValue, csvQuoteChar, quoteStr, doubleQuoteStr) }; } } if (parseMatchesAsRow) @@ -2852,7 +2868,7 @@ JNode matchEvaluator(string mValue, bool tryParseAsNumber, int jnodePosition) { header = new List(nColumns); for (int ii = minGroupNum; ii <= maxGroupNum; ii++) - header.Add(m.Groups[ii].Value); + header.Add(UnquoteCsvQuotedString(m.Groups[ii].Value, csvQuoteChar, quoteStr, doubleQuoteStr)); } } if (parseMatchesAsRow) diff --git a/JsonToolsNppPlugin/Main.cs b/JsonToolsNppPlugin/Main.cs index 8558d7f..aec1c8f 100644 --- a/JsonToolsNppPlugin/Main.cs +++ b/JsonToolsNppPlugin/Main.cs @@ -412,7 +412,6 @@ static internal void FileBeforeRename(IntPtr bufferRenamedId) static internal void FileRenamed(IntPtr bufferRenamedId) { string bufferNewName = Npp.notepad.GetFilePath(bufferRenamedId); - ValidateIfFilenameMatches(bufferNewName); if (bufferNewName == schemasToFnamePatternsFname) { ParseSchemasToFnamePatternsFile(); @@ -424,7 +423,7 @@ static internal void FileRenamed(IntPtr bufferRenamedId) if (TryGetInfoForFile(bufferOldName, out JsonFileInfo oldInfo)) { jsonFilesRenamed.Remove(bufferRenamedId); - oldInfo.tv?.Rename(bufferNewName); + oldInfo.tv?.Rename(bufferNewName, true); jsonFileInfos.Remove(bufferOldName); jsonFileInfos[bufferNewName] = oldInfo; } @@ -434,6 +433,7 @@ static internal void FileRenamed(IntPtr bufferRenamedId) grepperForm.tv.fname = bufferNewName; shouldRenameGrepperForm = false; } + ValidateIfFilenameMatches(bufferNewName); } static internal void FileRenameCancel(IntPtr bufferRenamedId) @@ -1340,7 +1340,9 @@ private static void DisplayErrorForm(ErrorForm form) NppTbData _nppTbData = new NppTbData(); _nppTbData.hClient = form.Handle; - _nppTbData.pszName = form.Text; + IntPtr ptrTitleBuf = Marshal.StringToHGlobalUni(form.Text); + errorForm.ptrTitleBuf = ptrTitleBuf; + _nppTbData.pszName = ptrTitleBuf; // the dlgDlg should be the index of funcItem where the current function pointer is in // this case is 15.. so the initial value of funcItem[15]._cmdID - not the updated internal one ! _nppTbData.dlgID = errorFormId; @@ -1349,8 +1351,8 @@ private static void DisplayErrorForm(ErrorForm form) _nppTbData.hIconTab = (uint)dockingFormIcon.Handle; _nppTbData.pszModuleName = PluginName; IntPtr _ptrNppTbData = Marshal.AllocHGlobal(Marshal.SizeOf(_nppTbData)); + errorForm.ptrNppTbData = _ptrNppTbData; Marshal.StructureToPtr(_nppTbData, _ptrNppTbData, false); - Win32.SendMessage(PluginBase.nppData._nppHandle, (uint)NppMsg.NPPM_DMMREGASDCKDLG, 0, _ptrNppTbData); Npp.notepad.ShowDockingForm(form); } @@ -1580,14 +1582,7 @@ public static void OpenJsonTree(DocumentType documentType = DocumentType.JSON) openTreeViewer = new TreeViewer(json); info.tv = openTreeViewer; jsonFileInfos[activeFname] = info; - DisplayJsonTree(openTreeViewer, json, GetNameForJsonTree(openTreeViewer), usesSelections, documentType, parserState == ParserState.FATAL); - } - - private static string GetNameForJsonTree(TreeViewer tv) - { - string defaultNameFormat = "Json Tree View for {0}"; - string nameFormat = (Translator.TryGetTranslationAtPath(new string[] { "forms", "TreeViewer", "title" }, out JNode node) && node.value is string s) ? s : defaultNameFormat; - return Translator.TryTranslateWithFormatting(defaultNameFormat, nameFormat, tv.RelativeFilename()); + DisplayJsonTree(openTreeViewer, json, activeFname, usesSelections, documentType, parserState == ParserState.FATAL); } static void OpenGrepperForm() @@ -1618,17 +1613,18 @@ public static void DisplayJsonTree(TreeViewer treeViewer, JNode json, string tit NppTbData _nppTbData = new NppTbData(); _nppTbData.hClient = treeViewer.Handle; - _nppTbData.pszName = title; + _nppTbData.pszName = treeViewer.SetTitleBuffer(title, grepperForm == null || grepperForm.tv == null || treeViewer != grepperForm.tv); // the dlgDlg should be the index of funcItem where the current function pointer is in // this case is 15.. so the initial value of funcItem[15]._cmdID - not the updated internal one ! _nppTbData.dlgID = jsonTreeId; // define the default docking behaviour - _nppTbData.uMask = NppTbMsg.DWS_DF_CONT_RIGHT | NppTbMsg.DWS_ICONTAB | NppTbMsg.DWS_ICONBAR; + _nppTbData.uMask = NppTbMsg.DWS_DF_CONT_RIGHT | NppTbMsg.DWS_ICONTAB | NppTbMsg.DWS_ICONBAR | NppTbMsg.DWS_ADDINFO; // DWS_ADDINFO necessary to allow changing name later _nppTbData.hIconTab = (uint)dockingFormIcon.Handle; _nppTbData.pszModuleName = PluginName; IntPtr _ptrNppTbData = Marshal.AllocHGlobal(Marshal.SizeOf(_nppTbData)); Marshal.StructureToPtr(_nppTbData, _ptrNppTbData, false); - + treeViewer.ptrNppTbData = _ptrNppTbData; + Npp.SetLangBasedOnDocType(fatalParserError, usesSelections, documentType); Win32.SendMessage(PluginBase.nppData._nppHandle, (uint)NppMsg.NPPM_DMMREGASDCKDLG, 0, _ptrNppTbData); // Following message will toogle both menu item state and toolbar button diff --git a/JsonToolsNppPlugin/PluginInfrastructure/Docking_h.cs b/JsonToolsNppPlugin/PluginInfrastructure/Docking_h.cs index bb256da..d6c7e20 100644 --- a/JsonToolsNppPlugin/PluginInfrastructure/Docking_h.cs +++ b/JsonToolsNppPlugin/PluginInfrastructure/Docking_h.cs @@ -43,7 +43,7 @@ public enum NppTbMsg : uint public struct NppTbData { public IntPtr hClient; // HWND: client Window Handle - public string pszName; // TCHAR*: name of plugin (shown in window) + public IntPtr pszName; // TCHAR*: name of plugin (shown in window) public int dlgID; // int: a funcItem provides the function pointer to start a dialog. Please parse here these ID // user modifications public NppTbMsg uMask; // UINT: mask params: look to above defines diff --git a/JsonToolsNppPlugin/PluginInfrastructure/ScintillaGateway.cs b/JsonToolsNppPlugin/PluginInfrastructure/ScintillaGateway.cs index ea5a126..63f1770 100644 --- a/JsonToolsNppPlugin/PluginInfrastructure/ScintillaGateway.cs +++ b/JsonToolsNppPlugin/PluginInfrastructure/ScintillaGateway.cs @@ -1781,6 +1781,11 @@ public void Clear() /// Replace the contents of the document with the argument text. (Scintilla feature 2181) public unsafe void SetText(string text) { + if (text.Length == 0) + { + ClearAll(); + return; + } fixed (byte* textPtr = Encoding.UTF8.GetBytes(text)) { Win32.SendMessage(scintilla, SciMsg.SCI_SETTEXT, (IntPtr) Unused, (IntPtr) textPtr); diff --git a/JsonToolsNppPlugin/Properties/AssemblyInfo.cs b/JsonToolsNppPlugin/Properties/AssemblyInfo.cs index 4f42941..3f213e2 100644 --- a/JsonToolsNppPlugin/Properties/AssemblyInfo.cs +++ b/JsonToolsNppPlugin/Properties/AssemblyInfo.cs @@ -28,5 +28,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion("8.1.0.3")] -[assembly: AssemblyFileVersion("8.1.0.3")] +[assembly: AssemblyVersion("8.1.0.4")] +[assembly: AssemblyFileVersion("8.1.0.4")] diff --git a/JsonToolsNppPlugin/Tests/JsonTabularizerTests.cs b/JsonToolsNppPlugin/Tests/JsonTabularizerTests.cs index fb2d5ab..30de5ed 100644 --- a/JsonToolsNppPlugin/Tests/JsonTabularizerTests.cs +++ b/JsonToolsNppPlugin/Tests/JsonTabularizerTests.cs @@ -503,12 +503,15 @@ public static bool Test() ( "[{\"a\": 1, \"b\": \"a,b\"}, {\"a\": 2, \"b\": \"c\"}]", "a,b\n1,'a,b'\n2,c\n", ',', '\'', null, false, "\n" ), // delims in values ( "[{\"a,b\": 1, \"b\": \"a\"}, {\"a,b\": 2, \"b\": \"b\"}]", "\"a,b\",b\r\n1,a\r\n2,b\r\n", ',', '"', null, false, "\r\n" ), ( "[{\"a,b\": 1, \"b\": \"a\"}, {\"a,b\": 2, \"b\": \"b\"}]", "'a,b',b\r\n1,a\r\n2,b\r\n", ',', '\'', null, false, "\r\n" ), - ( "[{\"a,b\": 1, \"b\": \"a\"}, {\"a,b\": 2, \"b\": \"b\"}]", // internal delims in column header + ("[{\"a\\\"b\": 1.5, \"c\": \"a\"}, {\"a\\\"b\": true, \"c\": null}]", "\"a\"\"b\"\tc\r1.5\ta\rtrue\t\r", '\t', '"', null, false, "\r"), // internal '"' in column header when '"' is quote char + ("[{\"a\\\"b\": true, \"c\": false}]", "c,\"a\"\"b\"\r\n0,1\r\n", ',', '"', new string[]{"c", "a\"b"}, true, "\r\n"), // internal '"' in column header when '"' is quote char, and header is user-supplied + ("[{\"a'b\": 1.5, \"c\": \"a\"}, {\"c\": null, \"a'b\": true}]", "'a''b'\tc\n1.5\ta\ntrue\t\n", '\t', '\'', null, false, "\n"), // internal quote char in column header (when '"' is not quote char) + ( "[{\"a,b\": 1, \"b\": \"a\"}, {\"a,b\": 2, \"b\": \"b\"}]", // internal delims in column header "b,\"a,b\"\r\na,1\r\nb,2\r\n", ',', '"', new string[]{"b", "a,b"}, false, "\r\n" ), ( "[{\"a\\tb\": 1, \"b\": \"a\"}, {\"a\\tb\": 2, \"b\": \"b\"}]", // \t in column header when \t is delim - "a\\tb\tb\r\n1\ta\r\n2\tb\r\n", + "\"a\tb\"\tb\r\n1\ta\r\n2\tb\r\n", '\t', '"', null, false, "\r\n" ), ( "[{\"a\": 1, \"b\": \"a\\tb\"}, {\"a\": 2, \"b\": \"c\"}]", diff --git a/JsonToolsNppPlugin/Tests/RemesPathTests.cs b/JsonToolsNppPlugin/Tests/RemesPathTests.cs index 44052a6..bd95dff 100644 --- a/JsonToolsNppPlugin/Tests/RemesPathTests.cs +++ b/JsonToolsNppPlugin/Tests/RemesPathTests.cs @@ -607,13 +607,13 @@ public static bool Test() ", 3, null, null, null, n, 0, -1)", "[[\"a\", \"-3\", NaN], [\"baz\", \"quz\", -Infinity]]"), // 4-column, map header to values, '\t' separator, '\n' newline, parse 2nd-to-last column as numbers - new Query_DesiredResult("s_csv(`col1\\tcol2\\tcol3\\tcol4\\n" + + new Query_DesiredResult("s_csv(`col1\\tcol2\\t\"col\"\"3\"\\tcol4\\n" + "ab\\tcd\\t0xfa\\tefg\\n" + "hi\\tjk\\t-5.3E000\\tlmn\\n" + "opq\\trs\\t.7e-11\\ttuv\\n" + "wx\\ty\\t+85\\tz`" + ", 4, `\\t`, `\\n`, , d, -2)", - "[{\"col1\":\"ab\",\"col2\":\"cd\",\"col3\":250,\"col4\":\"efg\"},{\"col1\":\"hi\",\"col2\":\"jk\",\"col3\":-5.3,\"col4\":\"lmn\"},{\"col1\":\"opq\",\"col2\":\"rs\",\"col3\":7E-12,\"col4\":\"tuv\"},{\"col1\":\"wx\",\"col2\":\"y\",\"col3\":85,\"col4\":\"z\"}]"), + "[{\"col1\":\"ab\",\"col2\":\"cd\",\"col\\\"3\":250,\"col4\":\"efg\"},{\"col1\":\"hi\",\"col2\":\"jk\",\"col\\\"3\":-5.3,\"col4\":\"lmn\"},{\"col1\":\"opq\",\"col2\":\"rs\",\"col\\\"3\":7E-12,\"col4\":\"tuv\"},{\"col1\":\"wx\",\"col2\":\"y\",\"col\\\"3\":85,\"col4\":\"z\"}]"), // 1-column, map header to values, '^' delimiter, '$' quote character, '\r' newline new Query_DesiredResult("s_csv(`a\\r" + "$b^c$\\r" + @@ -631,19 +631,22 @@ public static bool Test() ", 1, `^`, `\\r`, `$`, , 0)", // omit header arg because it is default "[1, 0.3, 5, -7.2]"), // 1-column, map header to values, '^' delimiter, '$' quote character, '\r' newline, parse as numbers - new Query_DesiredResult("s_csv(`foo\\r" + + new Query_DesiredResult("s_csv(`$foo$\\r" + "1\\r" + ".3\\r" + "5\\r" + "$-7.2$`" + ", 1, `^`, `\\r`, `$`, d, 0)", "[{\"foo\": 1}, {\"foo\": 0.3}, {\"foo\": 5}, {\"foo\": \"-7.2\"}]"), + // 1-column, map header to values, ',' delimiter, '\'' quote char, '\n' newline + new Query_DesiredResult("s_csv(`ba\\tz\\n'bl,ar'\\n5.75 qun`, 1, `,`, `\\n`, `'`, d)", + "[{\"ba\\tz\": \"bl,ar\"}, {\"ba\\tz\": \"5.75 qun\"}]"), // 2-column, map header to values, '|' delimiter, '$' quote char, '\r\n' newline, parse first col as numbers - new Query_DesiredResult("s_csv(`foo|bar\\r\\n" + + new Query_DesiredResult("s_csv(`foo|$$$bar$\\r\\n" + "1|3\\r\\n" + "-5.5|$3|4$\\r\\n" + "$$|`, 2, `|`, `\\r\\n`, `$`, d, 0)", - "[{\"foo\":1,\"bar\":\"3\"},{\"foo\":-5.5,\"bar\":\"3|4\"},{\"foo\":\"\",\"bar\":\"\"}]"), + "[{\"foo\":1,\"$bar\":\"3\"},{\"foo\":-5.5,\"$bar\":\"3|4\"},{\"foo\":\"\",\"$bar\":\"\"}]"), // 2-column, skip header, ']' delimiter, '\'' quote char, '\r\n' newline new Query_DesiredResult("s_csv(`foo]bar\\r\\n" + "1]3\\r\\n" + diff --git a/JsonToolsNppPlugin/Tests/UserInterfaceTests.cs b/JsonToolsNppPlugin/Tests/UserInterfaceTests.cs index d633bff..12cce84 100644 --- a/JsonToolsNppPlugin/Tests/UserInterfaceTests.cs +++ b/JsonToolsNppPlugin/Tests/UserInterfaceTests.cs @@ -776,6 +776,8 @@ public static bool Test() ("tree_query", new object[]{"s_csv(@, 1,`\\t`,`\\r\\n`,`'` ,h)"}), ("treenode_click", new object[]{new string[] { "1 : \"{\\\"ö\\\": \\\"3 4\\\"}\"" } }), ("treenode_click", new object[]{new string[] { "3 : \"{\\\"5\\\": [6]}\"" } }), + ("tree_query", new object[]{"@ = ``"}), // test that using RemesPath to clear text of document works + ("compare_text", new object[]{""}), }; var messages = new List(); diff --git a/docs/README.md b/docs/README.md index 2733cc3..c8a82b2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -366,7 +366,7 @@ Below is an example of searching *only direct children or grandchildren* (by unc *Added in version 1.2.0* -Some JSON also has a somewhat __tabular__ format, such that it is amenable to conversion to a CSV file. The JSON in this example is a particularly simple case of this. +Some JSON also has a somewhat __tabular__ format, such that it is amenable to conversion to a CSV file. The JSON in [this example](#json-tools-overview) is a particularly simple case of this. This app has a [form](/docs/json-to-csv.md) that allows conversion of such JSON to a tabular format. Remember that even if the JSON file as a whole can't be "tabularized" (or *can*, but you don't *want* to), you can use a RemesPath query to select the part that you want to tabularize. diff --git a/most recent errors.txt b/most recent errors.txt index eac6f8b..a79b785 100644 --- a/most recent errors.txt +++ b/most recent errors.txt @@ -1,4 +1,4 @@ -Test results for JsonTools v8.1.0.3 on Notepad++ 8.6.9 64bit +Test results for JsonTools v8.1.0.4 on Notepad++ 8.6.9 64bit NOTE: Ctrl-F (regular expressions *on*) for "Failed [1-9]\d*" to find all failed tests Tests failed: YAML dumper ========================= @@ -107,7 +107,7 @@ Testing RemesPath parser and compiler The queried JSON in the RemesParser tests is named foo:{"foo": [[0, 1, 2], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]], "bar": {"a": false, "b": ["a`g", "bah"]}, "baz": "z", "quz": {}, "jub": [], "guzo": [[[1]], [[2], [3]]], "7": [{"foo": 2}, 1], "_": {"0": 0}} Failed 0 tests. -Passed 529 tests. +Passed 530 tests. ========================= Testing RemesPath throws errors on bad inputs ========================= @@ -152,7 +152,7 @@ Testing JSON tabularizer ========================= Failed 0 tests. -Passed 61 tests. +Passed 64 tests. ========================= Testing CSV sniffer ========================= @@ -199,40 +199,40 @@ Testing UI tests ========================= Failed 0 tests -Passed 346 tests +Passed 348 tests ========================= Testing JsonParser performance ========================= Preview of json: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... -To convert JSON string of size 89556 into JNode took 2.928 +/- 2.167 ms over 32 trials -Load times (ms): 2, 1, 1, 5, 1, 2, 7, 9, 1, 1, 3, 1, 1, 6, 1, 1, 1, 3, 1, 1, 6, 1, 1, 1, 4, 1, 1, 6, 1, 1, 1, 4 +To convert JSON string of size 89556 into JNode took 3.052 +/- 2.149 ms over 32 trials +Load times (ms): 2, 1, 2, 6, 2, 1, 1, 4, 1, 1, 7, 1, 1, 1, 4, 1, 1, 6, 1, 1, 1, 5, 1, 2, 6, 1, 1, 1, 7, 2, 1, 7 ========================= Performance tests for RemesPath (float arithmetic) ========================= -Compiling query "@[@[:].a * @[:].t < @[:].e]" took 0.064 ms the first time, including approximately 0.124 ms to tokenize the query. Subsequent executions are effectively free due to caching. -To run pre-compiled query "@[@[:].a * @[:].t < @[:].e]" on JNode from JSON of size 89556 into took 0.024 +/- 0.007 ms over 40 trials -Query times (ms): 0.063, 0.033, 0.022, 0.023, 0.022, 0.022, 0.022, 0.028, 0.023, 0.022, 0.022, 0.022, 0.022, 0.025, 0.022, 0.022, 0.023, 0.022, 0.022, 0.024, 0.023, 0.022, 0.022, 0.023, 0.022, 0.024, 0.022, 0.023, 0.022, 0.022, 0.022, 0.025, 0.022, 0.022, 0.022, 0.023, 0.022, 0.026, 0.022, 0.022 +Compiling query "@[@[:].a * @[:].t < @[:].e]" took 0.056 ms the first time, including approximately 0.092 ms to tokenize the query. Subsequent executions are effectively free due to caching. +To run pre-compiled query "@[@[:].a * @[:].t < @[:].e]" on JNode from JSON of size 89556 into took 0.045 +/- 0.013 ms over 40 trials +Query times (ms): 0.106, 0.072, 0.052, 0.04, 0.04, 0.041, 0.042, 0.058, 0.039, 0.037, 0.039, 0.038, 0.038, 0.051, 0.039, 0.038, 0.044, 0.062, 0.042, 0.062, 0.042, 0.044, 0.04, 0.041, 0.038, 0.059, 0.037, 0.038, 0.039, 0.039, 0.039, 0.054, 0.04, 0.038, 0.038, 0.041, 0.041, 0.059, 0.035, 0.037 Preview of result: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... ========================= Performance tests for RemesPath (string operations) ========================= -Compiling query "@[@[:].z =~ `(?i)[a-z]{5}`]" took 0.072 ms the first time, including approximately 0.155 ms to tokenize the query. Subsequent executions are effectively free due to caching. -To run pre-compiled query "@[@[:].z =~ `(?i)[a-z]{5}`]" on JNode from JSON of size 89556 into took 0.055 +/- 0.008 ms over 40 trials -Query times (ms): 0.098, 0.057, 0.054, 0.053, 0.055, 0.052, 0.053, 0.053, 0.052, 0.052, 0.054, 0.053, 0.053, 0.054, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.053, 0.054, 0.053, 0.053, 0.078, 0.056, 0.053, 0.053, 0.052, 0.052, 0.053, 0.052, 0.053, 0.053, 0.052, 0.053, 0.052, 0.052, 0.052, 0.053 +Compiling query "@[@[:].z =~ `(?i)[a-z]{5}`]" took 0.053 ms the first time, including approximately 0.057 ms to tokenize the query. Subsequent executions are effectively free due to caching. +To run pre-compiled query "@[@[:].z =~ `(?i)[a-z]{5}`]" on JNode from JSON of size 89556 into took 0.087 +/- 0.028 ms over 40 trials +Query times (ms): 0.179, 0.149, 0.101, 0.1, 0.121, 0.105, 0.102, 0.107, 0.102, 0.1, 0.099, 0.1, 0.106, 0.109, 0.102, 0.104, 0.108, 0.105, 0.103, 0.108, 0.086, 0.058, 0.073, 0.057, 0.056, 0.059, 0.07, 0.066, 0.06, 0.072, 0.058, 0.059, 0.059, 0.057, 0.071, 0.059, 0.064, 0.073, 0.057, 0.055 Preview of result: [{"A": "\n]o1VQ5t6g", "a": 4710024278, "b": 3268860721, "B": "g4Y7+ew^.v", "C": "NK nmax_notq, `when q=true, nmax = ` + str(nmax_q), `when q=false, nmax= ` + str(nmax_notq))" took 0.139 ms the first time, including approximately 0.177 ms to tokenize the query. Subsequent executions are effectively free due to caching. +ifelse(nmax_q > nmax_notq, `when q=true, nmax = ` + str(nmax_q), `when q=false, nmax= ` + str(nmax_notq))" took 0.254 ms the first time, including approximately 0.226 ms to tokenize the query. Subsequent executions are effectively free due to caching. To run pre-compiled query "var qmask = @[:].q; var nmax_q = max(@[qmask].n); var nmax_notq = max(@[not qmask].n); -ifelse(nmax_q > nmax_notq, `when q=true, nmax = ` + str(nmax_q), `when q=false, nmax= ` + str(nmax_notq))" on JNode from JSON of size 89556 into took 0.036 +/- 0.057 ms over 40 trials -Query times (ms): 0.101, 0.031, 0.017, 0.016, 0.028, 0.015, 0.016, 0.019, 0.233, 0.016, 0.023, 0.015, 0.082, 0.015, 0.017, 0.016, 0.015, 0.015, 0.015, 0.024, 0.014, 0.027, 0.015, 0.015, 0.015, 0.015, 0.015, 0.016, 0.016, 0.119, 0.048, 0.016, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.293, 0.017 +ifelse(nmax_q > nmax_notq, `when q=true, nmax = ` + str(nmax_q), `when q=false, nmax= ` + str(nmax_notq))" on JNode from JSON of size 89556 into took 0.028 +/- 0.02 ms over 40 trials +Query times (ms): 0.139, 0.034, 0.029, 0.028, 0.028, 0.043, 0.058, 0.034, 0.028, 0.028, 0.031, 0.022, 0.019, 0.017, 0.017, 0.017, 0.017, 0.017, 0.016, 0.017, 0.017, 0.016, 0.017, 0.022, 0.022, 0.019, 0.018, 0.02, 0.017, 0.018, 0.027, 0.024, 0.024, 0.03, 0.027, 0.031, 0.039, 0.03, 0.028, 0.028 Preview of result: "when q=false, nmax= 9830935647.0" ... ========================= @@ -271,11 +271,11 @@ Performance tests for RemesPath (references to compile-time constant variables) Compiling query "var X = X; var onetwo = j`[1, 2]`; -@[:]->at(@, X)->at(@, onetwo)" took 0.074 ms the first time, including approximately 0.078 ms to tokenize the query. Subsequent executions are effectively free due to caching. +@[:]->at(@, X)->at(@, onetwo)" took 0.076 ms the first time, including approximately 0.101 ms to tokenize the query. Subsequent executions are effectively free due to caching. To run pre-compiled query "var X = X; var onetwo = j`[1, 2]`; -@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.013 +/- 0.006 ms over 40 trials -Query times (ms): 0.05, 0.013, 0.012, 0.012, 0.017, 0.012, 0.012, 0.012, 0.012, 0.011, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.013, 0.012, 0.012, 0.012, 0.012, 0.013, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012, 0.012 +@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.032 +/- 0.065 ms over 40 trials +Query times (ms): 0.077, 0.046, 0.024, 0.02, 0.023, 0.025, 0.433, 0.029, 0.022, 0.022, 0.012, 0.011, 0.012, 0.012, 0.012, 0.012, 0.013, 0.012, 0.012, 0.021, 0.022, 0.019, 0.011, 0.012, 0.012, 0.02, 0.021, 0.022, 0.024, 0.023, 0.021, 0.03, 0.024, 0.024, 0.023, 0.024, 0.024, 0.022, 0.022, 0.023 Preview of result: [[1695727848, 0.28756263873668497], [2126430375, 0.0076779412970817704], [5310550656, 0.38076977264568701], [2519183283, 0.15317622093055799], [6610062385, 0.66299622587066598], [987168256, 0.92441018999992797], [6615003609, 0.91711269122594696], [4465232046, 0.68431193185153605], [8654414565, 0.631 ... ========================= @@ -284,29 +284,29 @@ Performance tests for RemesPath (references to variables that are not compile-ti Compiling query "var X = @->`X`; var onetwo = @{1, 2}; -@[:]->at(@, X)->at(@, onetwo)" took 0.104 ms the first time, including approximately 0.168 ms to tokenize the query. Subsequent executions are effectively free due to caching. +@[:]->at(@, X)->at(@, onetwo)" took 0.109 ms the first time, including approximately 0.113 ms to tokenize the query. Subsequent executions are effectively free due to caching. To run pre-compiled query "var X = @->`X`; var onetwo = @{1, 2}; -@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.021 +/- 0.017 ms over 40 trials -Query times (ms): 0.114, 0.016, 0.023, 0.016, 0.015, 0.016, 0.027, 0.015, 0.016, 0.016, 0.015, 0.016, 0.017, 0.053, 0.016, 0.016, 0.022, 0.024, 0.05, 0.015, 0.015, 0.025, 0.016, 0.016, 0.016, 0.015, 0.016, 0.016, 0.016, 0.015, 0.016, 0.015, 0.016, 0.016, 0.015, 0.015, 0.016, 0.015, 0.016, 0.016 +@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.03 +/- 0.019 ms over 40 trials +Query times (ms): 0.094, 0.033, 0.034, 0.115, 0.058, 0.029, 0.03, 0.028, 0.028, 0.032, 0.029, 0.031, 0.032, 0.027, 0.017, 0.017, 0.015, 0.016, 0.017, 0.016, 0.016, 0.016, 0.016, 0.017, 0.017, 0.018, 0.018, 0.017, 0.028, 0.03, 0.032, 0.032, 0.029, 0.032, 0.029, 0.031, 0.03, 0.033, 0.031, 0.031 Preview of result: [[1695727848, 0.28756263873668497], [2126430375, 0.0076779412970817704], [5310550656, 0.38076977264568701], [2519183283, 0.15317622093055799], [6610062385, 0.66299622587066598], [987168256, 0.92441018999992797], [6615003609, 0.91711269122594696], [4465232046, 0.68431193185153605], [8654414565, 0.631 ... ========================= Performance tests for RemesPath (simple string mutations) ========================= -Compiling query "@[:].z = s_sub(@, g, B)" took 0.048 ms the first time, including approximately 0.049 ms to tokenize the query. Subsequent executions are effectively free due to caching. -To run pre-compiled query "@[:].z = s_sub(@, g, B)" on JNode from JSON of size 89556 into took 0.013 +/- 0.004 ms over 40 trials -Query times (ms): 0.027, 0.015, 0.012, 0.009, 0.009, 0.011, 0.015, 0.015, 0.02, 0.017, 0.015, 0.015, 0.014, 0.013, 0.025, 0.013, 0.01, 0.01, 0.01, 0.011, 0.01, 0.011, 0.01, 0.011, 0.009, 0.012, 0.013, 0.015, 0.016, 0.013, 0.01, 0.01, 0.012, 0.012, 0.011, 0.012, 0.011, 0.011, 0.011, 0.009 +Compiling query "@[:].z = s_sub(@, g, B)" took 0.082 ms the first time, including approximately 0.116 ms to tokenize the query. Subsequent executions are effectively free due to caching. +To run pre-compiled query "@[:].z = s_sub(@, g, B)" on JNode from JSON of size 89556 into took 0.04 +/- 0.021 ms over 40 trials +Query times (ms): 0.05, 0.044, 0.034, 0.034, 0.045, 0.044, 0.047, 0.033, 0.042, 0.036, 0.04, 0.044, 0.039, 0.047, 0.046, 0.038, 0.026, 0.155, 0.035, 0.029, 0.025, 0.017, 0.026, 0.025, 0.023, 0.036, 0.027, 0.042, 0.047, 0.042, 0.027, 0.028, 0.025, 0.038, 0.036, 0.045, 0.039, 0.078, 0.035, 0.029 Preview of result: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... ========================= Performance tests for RemesPath (simple number mutations) ========================= -Compiling query "@[:].x = ifelse(@ < 0.5, @ + 3, @ - 3)" took 0.084 ms the first time, including approximately 0.114 ms to tokenize the query. Subsequent executions are effectively free due to caching. -To run pre-compiled query "@[:].x = ifelse(@ < 0.5, @ + 3, @ - 3)" on JNode from JSON of size 89556 into took 0.023 +/- 0.01 ms over 40 trials -Query times (ms): 0.035, 0.019, 0.018, 0.018, 0.019, 0.018, 0.018, 0.019, 0.018, 0.018, 0.019, 0.019, 0.075, 0.033, 0.02, 0.019, 0.019, 0.02, 0.021, 0.022, 0.038, 0.022, 0.019, 0.022, 0.023, 0.025, 0.024, 0.025, 0.019, 0.018, 0.024, 0.026, 0.019, 0.023, 0.02, 0.019, 0.018, 0.019, 0.019, 0.025 +Compiling query "@[:].x = ifelse(@ < 0.5, @ + 3, @ - 3)" took 0.104 ms the first time, including approximately 0.122 ms to tokenize the query. Subsequent executions are effectively free due to caching. +To run pre-compiled query "@[:].x = ifelse(@ < 0.5, @ + 3, @ - 3)" on JNode from JSON of size 89556 into took 0.035 +/- 0.011 ms over 40 trials +Query times (ms): 0.068, 0.054, 0.041, 0.044, 0.021, 0.036, 0.037, 0.029, 0.02, 0.025, 0.04, 0.022, 0.042, 0.039, 0.037, 0.031, 0.02, 0.021, 0.023, 0.03, 0.037, 0.045, 0.038, 0.036, 0.038, 0.036, 0.05, 0.048, 0.035, 0.026, 0.023, 0.026, 0.026, 0.023, 0.021, 0.034, 0.04, 0.043, 0.046, 0.047 Preview of result: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... ========================= @@ -316,12 +316,12 @@ Performance tests for RemesPath (mutations with a for loop) Compiling query "var xhalf = @[:].x < 0.5; for lx = zip(@[:].l, xhalf); lx[0] = ifelse(lx[1], foo, bar); -end for;" took 0.164 ms the first time, including approximately 0.109 ms to tokenize the query. Subsequent executions are effectively free due to caching. +end for;" took 0.211 ms the first time, including approximately 0.162 ms to tokenize the query. Subsequent executions are effectively free due to caching. To run pre-compiled query "var xhalf = @[:].x < 0.5; for lx = zip(@[:].l, xhalf); lx[0] = ifelse(lx[1], foo, bar); -end for;" on JNode from JSON of size 89556 into took 0.044 +/- 0.019 ms over 40 trials -Query times (ms): 0.097, 0.04, 0.04, 0.038, 0.038, 0.038, 0.037, 0.039, 0.037, 0.058, 0.133, 0.079, 0.039, 0.036, 0.036, 0.036, 0.036, 0.035, 0.035, 0.036, 0.05, 0.036, 0.034, 0.049, 0.042, 0.036, 0.035, 0.035, 0.036, 0.035, 0.035, 0.037, 0.038, 0.038, 0.036, 0.057, 0.041, 0.037, 0.039, 0.037 +end for;" on JNode from JSON of size 89556 into took 0.074 +/- 0.024 ms over 40 trials +Query times (ms): 0.083, 0.05, 0.083, 0.085, 0.044, 0.062, 0.061, 0.074, 0.046, 0.058, 0.067, 0.106, 0.096, 0.084, 0.071, 0.079, 0.115, 0.092, 0.113, 0.105, 0.081, 0.05, 0.064, 0.08, 0.057, 0.071, 0.072, 0.048, 0.042, 0.076, 0.057, 0.043, 0.071, 0.066, 0.094, 0.072, 0.07, 0.06, 0.16, 0.05 Preview of result: [["bar", false], ["bar", false], ["foo", true], ["foo", true], ["foo", true], ["foo", true], ["foo", true], ["bar", false], ["bar", false], ["bar", false], ["foo", true], ["foo", true], ["bar", false], ["bar", false], ["foo", true], ["bar", false], ["bar", false], ["bar", false], ["foo", true], ["ba ... ========================= @@ -330,32 +330,32 @@ Testing performance of JSON compression and pretty-printing Preview of json: [{"A": "Ky'c^g#~)0", "a": 1850111954, "b": 9318359041, "B": "Oyi:/ xxe2", "C": "sKCSa_^7Gg", "c": 7974777124, "d": 2670309238, "D": "0d_K)HmX!.", "E": ".uM*Z{0EJ_", "e": 6958410336, "f": 8050244728, "F": "1%SG_A!xB\t", "g": 3799657125, "G": "il1^k\\\nat*", "H": {"a": 6079042826, "b": 7292804611, "c" ... -To compress JNode from JSON string of 89556 took 4.404 +/- 1.087 ms over 64 trials (minimal whitespace, sortKeys=TRUE) -To compress JNode from JSON string of 89556 took 2.481 +/- 0.335 ms over 64 trials (minimal whitespace, sortKeys=FALSE) -To Google-style pretty-print JNode from JSON string of 89556 took 4.836 +/- 0.491 ms over 64 trials (sortKeys=true, indent=4) -To Whitesmith-style pretty-print JNode from JSON string of 89556 took 4.591 +/- 0.862 ms over 64 trials (sortKeys=true, indent=4) -To PPrint-style pretty-print JNode from JSON string of 89556 took 6.066 +/- 0.637 ms over 64 trials (sortKeys=true, indent=4) +To compress JNode from JSON string of 89556 took 4.684 +/- 1.108 ms over 64 trials (minimal whitespace, sortKeys=TRUE) +To compress JNode from JSON string of 89556 took 2.109 +/- 0.329 ms over 64 trials (minimal whitespace, sortKeys=FALSE) +To Google-style pretty-print JNode from JSON string of 89556 took 4.286 +/- 0.266 ms over 64 trials (sortKeys=true, indent=4) +To Whitesmith-style pretty-print JNode from JSON string of 89556 took 4.44 +/- 0.558 ms over 64 trials (sortKeys=true, indent=4) +To PPrint-style pretty-print JNode from JSON string of 89556 took 6.317 +/- 0.445 ms over 64 trials (sortKeys=true, indent=4) ========================= Testing performance of JsonSchemaValidator and random JSON creation ========================= -To create a random set of JSON from file at path C:\Program Files\Notepad++\plugins\JsonTools\testfiles\tweet_schema.json of size 184326 (array of 15 items) based on the matching schema took 6.595 +/- 2.757 ms over 25 trials -To compile the schema to a validation function took 0.33 +/- 0.544 ms over 25 trials -To validate JSON of size 184326 (array of 15 items) based on the compiled schema took 1.051 +/- 0.2 ms over 25 trials +To create a random set of JSON from file at path C:\Program Files\Notepad++\plugins\JsonTools\testfiles\tweet_schema.json of size 159902 (array of 15 items) based on the matching schema took 7.084 +/- 3.314 ms over 25 trials +To compile the schema to a validation function took 0.219 +/- 0.028 ms over 25 trials +To validate JSON of size 159902 (array of 15 items) based on the compiled schema took 1.062 +/- 0.161 ms over 25 trials ========================= Testing performance of random JSON from schema with patterns and patternProperties ========================= -To create a random set of JSON from string (see TestRunner.cs) of size 29841 (array of 120 items) based on the matching schema took 1.438 +/- 0.669 ms over 25 trials -To compile the schema to a validation function took 0.348 +/- 0.508 ms over 25 trials -To validate JSON of size 29841 (array of 120 items) based on the compiled schema took 8.877 +/- 0.255 ms over 25 trials +To create a random set of JSON from string (see TestRunner.cs) of size 29973 (array of 120 items) based on the matching schema took 1.52 +/- 0.7 ms over 25 trials +To compile the schema to a validation function took 0.267 +/- 0.024 ms over 25 trials +To validate JSON of size 29973 (array of 120 items) based on the compiled schema took 9.55 +/- 0.397 ms over 25 trials ========================= Testing performance of random JSON from schema *ignoring* patterns and patternProperties ========================= -To create a random set of JSON from string (see TestRunner.cs) of size 10853 (array of 120 items) based on the matching schema took 0.831 +/- 0.516 ms over 25 trials -To compile the schema to a validation function took 0.21 +/- 0.007 ms over 25 trials -To validate JSON of size 10853 (array of 120 items) based on the compiled schema took 5.334 +/- 0.223 ms over 25 trials +To create a random set of JSON from string (see TestRunner.cs) of size 10800 (array of 120 items) based on the matching schema took 0.866 +/- 0.468 ms over 25 trials +To compile the schema to a validation function took 0.242 +/- 0.036 ms over 25 trials +To validate JSON of size 10800 (array of 120 items) based on the compiled schema took 6.161 +/- 0.989 ms over 25 trials ========================= Testing JSON grepper's API request tool =========================