From 8d119a2a56140154054275eeffa234690ade4424 Mon Sep 17 00:00:00 2001 From: molsonkiko <46202915+molsonkiko@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:53:17 -0700 Subject: [PATCH] Add path_separator setting (fix #69) Also improve treenode right-click context menu --- CHANGELOG.md | 5 +- .../Forms/TreeViewer.Designer.cs | 48 ++++--- JsonToolsNppPlugin/Forms/TreeViewer.cs | 111 ++++++++++++++-- JsonToolsNppPlugin/Forms/TreeViewer.resx | 8 +- JsonToolsNppPlugin/JSONTools/JNode.cs | 120 ++++++++++-------- JsonToolsNppPlugin/Main.cs | 85 +++++++++---- .../PluginInfrastructure/SettingsBase.cs | 14 +- JsonToolsNppPlugin/Properties/AssemblyInfo.cs | 4 +- JsonToolsNppPlugin/Tests/FormatPathTests.cs | 56 ++++++-- .../Tests/UserInterfaceTests.cs | 6 + JsonToolsNppPlugin/Utils/Settings.cs | 6 +- docs/README.md | 28 ++-- most recent errors.txt | 84 ++++++------ translation/english.json5 | 3 +- translation/italian.json5 | 5 +- 15 files changed, 404 insertions(+), 179 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c4e29a..2f55349 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). * Add `uses_context` field to ArgFunction instances, so that they have JQueryContext appended to their arguments, and they can reference fields of that JQueryContext. * This way we don't have to have these methods mutating and referencing a global static variable. * Additionally, the presence of a function with `uses_context=true` would serve as a flag that the query cannot be executed in parallel, because doing so would cause race conditions associated with the shared JQueryContext fields. -7. Unit tests that randomly generate text with JSON chars to make sure JSON parser never throws for any reason, since errors aren't caught. ### To Be Changed @@ -57,6 +56,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). 2. In the `grepper form`, pressing `Enter` inside the `Previously viewed directories...` box causes the current text of the box to be searched, assuming that it is a valid directory. 3. [Translation](/README.md#translating-jsontools-to-another-language) of settings in the [Settings form](/docs/README.md#customizing-settings). 4. Translation of [JSON syntax errors and JSON schema validation errors](/docs/README.md#error-form-and-status-bar) (under the `jsonLint` field of the [translation file](/translation/english.json5)) +5. The [`path_separator` setting](/docs/README.md#key_style-and-path_separator-settings) for formatting keys/indices and paths. Addresses [issue 69](https://github.com/molsonkiko/JsonToolsNppPlugin/issues/69). +6. Make it so left-clicking on the `Key/index to clipboard` and `Path to clipboard` options of the [treenode right-click context menu](/docs/README.md#get-info-about-tree-nodes) gets the path or key/index in whatever the default is from your settings, without having to click on one of the sub-menu items. ### Changed @@ -813,7 +814,7 @@ __[.NET Framework 4.8](https://learn.microsoft.com/en-us/dotnet/framework/migrat 1. [Menu command](/docs/README.md#path-to-current-line) for getting path to first node in current line. 2. Right-clicking on tree nodes lets you get the current node's value, key/index in parent iterable, or path. -3. [key_style](/docs/README.md#key-style) option in settings for customizing how the path is formatted (e.g., dot syntax for JavaScript vs. obligatory square brackets and quotes for Python) +3. [key_style](/docs/README.md#key_style-and-path_separator-settings) option in settings for customizing how the path is formatted (e.g., dot syntax for JavaScript vs. obligatory square brackets and quotes for Python) 4. Automatic resizing of the query box and the tree view when the docking box is resized. 5. A text box containing the path to the currently selected tree node (in the default key style) and a [button for copying it to the clipboard](/docs/README.md#get-info-about-tree-nodes). diff --git a/JsonToolsNppPlugin/Forms/TreeViewer.Designer.cs b/JsonToolsNppPlugin/Forms/TreeViewer.Designer.cs index 9d5d74a..8f6e469 100644 --- a/JsonToolsNppPlugin/Forms/TreeViewer.Designer.cs +++ b/JsonToolsNppPlugin/Forms/TreeViewer.Designer.cs @@ -55,7 +55,7 @@ private void InitializeComponent() this.PythonStyleItem = new System.Windows.Forms.ToolStripMenuItem(); this.RemesPathStyleItem = new System.Windows.Forms.ToolStripMenuItem(); this.CopyPathItem = new System.Windows.Forms.ToolStripMenuItem(); - this.JavaScriptStyleKeyItem = new System.Windows.Forms.ToolStripMenuItem(); + this.JavaScriptStylePathItem = new System.Windows.Forms.ToolStripMenuItem(); this.PythonStylePathItem = new System.Windows.Forms.ToolStripMenuItem(); this.RemesPathStylePathItem = new System.Windows.Forms.ToolStripMenuItem(); this.ToggleSubtreesItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -66,6 +66,8 @@ private void InitializeComponent() this.RefreshButton = new System.Windows.Forms.Button(); this.FindReplaceButton = new System.Windows.Forms.Button(); this.DocumentTypeComboBox = new System.Windows.Forms.ComboBox(); + this.path_separatorStyleItem = new System.Windows.Forms.ToolStripMenuItem(); + this.path_separatorStylePathItem = new System.Windows.Forms.ToolStripMenuItem(); this.NodeRightClickMenu.SuspendLayout(); this.SuspendLayout(); // @@ -170,7 +172,7 @@ private void InitializeComponent() this.OpenSortFormItem, this.SelectAllChildrenItem}); this.NodeRightClickMenu.Name = "NodeRightClickMenu"; - this.NodeRightClickMenu.Size = new System.Drawing.Size(268, 172); + this.NodeRightClickMenu.Size = new System.Drawing.Size(268, 200); // // CopyValueMenuItem // @@ -183,7 +185,8 @@ private void InitializeComponent() this.CopyKeyItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.JavaScriptStyleItem, this.PythonStyleItem, - this.RemesPathStyleItem}); + this.RemesPathStyleItem, + this.path_separatorStyleItem}); this.CopyKeyItem.Name = "CopyKeyItem"; this.CopyKeyItem.Size = new System.Drawing.Size(267, 24); this.CopyKeyItem.Text = "Key/index to clipboard"; @@ -191,47 +194,48 @@ private void InitializeComponent() // JavaScriptStyleItem // this.JavaScriptStyleItem.Name = "JavaScriptStyleItem"; - this.JavaScriptStyleItem.Size = new System.Drawing.Size(198, 26); + this.JavaScriptStyleItem.Size = new System.Drawing.Size(268, 26); this.JavaScriptStyleItem.Text = "JavaScript style"; // // PythonStyleItem // this.PythonStyleItem.Name = "PythonStyleItem"; - this.PythonStyleItem.Size = new System.Drawing.Size(198, 26); + this.PythonStyleItem.Size = new System.Drawing.Size(268, 26); this.PythonStyleItem.Text = "Python style"; // // RemesPathStyleItem // this.RemesPathStyleItem.Name = "RemesPathStyleItem"; - this.RemesPathStyleItem.Size = new System.Drawing.Size(198, 26); + this.RemesPathStyleItem.Size = new System.Drawing.Size(268, 26); this.RemesPathStyleItem.Text = "RemesPath style"; // // CopyPathItem // this.CopyPathItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.JavaScriptStyleKeyItem, + this.JavaScriptStylePathItem, this.PythonStylePathItem, - this.RemesPathStylePathItem}); + this.RemesPathStylePathItem, + this.path_separatorStylePathItem}); this.CopyPathItem.Name = "CopyPathItem"; this.CopyPathItem.Size = new System.Drawing.Size(267, 24); this.CopyPathItem.Text = "Path to clipboard"; // - // JavaScriptStyleKeyItem + // JavaScriptStylePathItem // - this.JavaScriptStyleKeyItem.Name = "JavaScriptStyleKeyItem"; - this.JavaScriptStyleKeyItem.Size = new System.Drawing.Size(198, 26); - this.JavaScriptStyleKeyItem.Text = "JavaScript style"; + this.JavaScriptStylePathItem.Name = "JavaScriptStylePathItem"; + this.JavaScriptStylePathItem.Size = new System.Drawing.Size(268, 26); + this.JavaScriptStylePathItem.Text = "JavaScript style"; // // PythonStylePathItem // this.PythonStylePathItem.Name = "PythonStylePathItem"; - this.PythonStylePathItem.Size = new System.Drawing.Size(198, 26); + this.PythonStylePathItem.Size = new System.Drawing.Size(268, 26); this.PythonStylePathItem.Text = "Python style"; // // RemesPathStylePathItem // this.RemesPathStylePathItem.Name = "RemesPathStylePathItem"; - this.RemesPathStylePathItem.Size = new System.Drawing.Size(198, 26); + this.RemesPathStylePathItem.Size = new System.Drawing.Size(268, 26); this.RemesPathStylePathItem.Text = "RemesPath style"; // // ToggleSubtreesItem @@ -314,6 +318,18 @@ private void InitializeComponent() this.DocumentTypeComboBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.QueryBox_KeyPress); this.DocumentTypeComboBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.TreeViewer_KeyUp); // + // path_separatorStyleItem + // + this.path_separatorStyleItem.Name = "path_separatorStyleItem"; + this.path_separatorStyleItem.Size = new System.Drawing.Size(268, 26); + this.path_separatorStyleItem.Text = "Use path_separator setting"; + // + // path_separatorStylePathItem + // + this.path_separatorStylePathItem.Name = "path_separatorStylePathItem"; + this.path_separatorStylePathItem.Size = new System.Drawing.Size(268, 26); + this.path_separatorStylePathItem.Text = "Use path_separator setting"; + // // TreeViewer // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); @@ -350,7 +366,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem PythonStyleItem; private System.Windows.Forms.ToolStripMenuItem RemesPathStyleItem; private System.Windows.Forms.ToolStripMenuItem CopyPathItem; - private System.Windows.Forms.ToolStripMenuItem JavaScriptStyleKeyItem; + private System.Windows.Forms.ToolStripMenuItem JavaScriptStylePathItem; private System.Windows.Forms.ToolStripMenuItem PythonStylePathItem; private System.Windows.Forms.ToolStripMenuItem RemesPathStylePathItem; private System.Windows.Forms.TextBox CurrentPathBox; @@ -364,5 +380,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem SelectThisItem; private System.Windows.Forms.ToolStripMenuItem SelectAllChildrenItem; private System.Windows.Forms.ComboBox DocumentTypeComboBox; + private System.Windows.Forms.ToolStripMenuItem path_separatorStyleItem; + private System.Windows.Forms.ToolStripMenuItem path_separatorStylePathItem; } } \ No newline at end of file diff --git a/JsonToolsNppPlugin/Forms/TreeViewer.cs b/JsonToolsNppPlugin/Forms/TreeViewer.cs index 17a3658..e6851ce 100644 --- a/JsonToolsNppPlugin/Forms/TreeViewer.cs +++ b/JsonToolsNppPlugin/Forms/TreeViewer.cs @@ -72,13 +72,18 @@ public partial class TreeViewer : Form public bool isDarkMode = false; // event handlers for the node mouseclick drop down menu + private bool hasWarnedNo_path_separator = false; private static MouseEventHandler valToClipboardHandler = null; + private static MouseEventHandler pathToClipboardHandler = null; private static MouseEventHandler pathToClipboardHandler_Remespath = null; private static MouseEventHandler pathToClipboardHandler_Python = null; private static MouseEventHandler pathToClipboardHandler_Javascript = null; + private static MouseEventHandler pathToClipboardHandler_path_separator = null; + private static MouseEventHandler keyToClipboardHandler = null; private static MouseEventHandler keyToClipboardHandler_Remespath = null; private static MouseEventHandler keyToClipboardHandler_Python = null; private static MouseEventHandler keyToClipboardHandler_Javascript = null; + private static MouseEventHandler keyToClipboardHandler_path_separator = null; private static MouseEventHandler ToggleSubtreesHandler = null; private static MouseEventHandler selectThisHandler = null; private static MouseEventHandler showSortFormHandler = null; @@ -924,6 +929,30 @@ private void Tree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) } ); keyToClipboard_RemesPath.MouseUp += keyToClipboardHandler_Remespath; + var keyToClipboard_path_separator = keyToClipboard.DropDownItems[3]; + keyToClipboard_path_separator.Text = $"Use path_separator setting ({Main.settings.path_separator})"; + if (keyToClipboardHandler_path_separator != null) + { + try + { + keyToClipboard_path_separator.MouseUp -= keyToClipboardHandler_path_separator; + } + catch { } + } + keyToClipboardHandler_path_separator = new MouseEventHandler( + (s2, e2) => + { + if (Main.pathSeparator == JNode.DEFAULT_PATH_SEPARATOR && !hasWarnedNo_path_separator) + { + MessageBox.Show($"You chose \"Key/index to clipboard\" with the \"Use path_separator setting\" option, but your path_separator is still the default {Main.settings.path_separator}. The {Main.settings.key_style} style is being used instead.", + "path_separator setting not configured", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + hasWarnedNo_path_separator = true; + } + Npp.TryCopyToClipboard(KeyOfTreeNode(node, Main.settings.key_style, Main.pathSeparator)); + } + ); + keyToClipboard_path_separator.MouseUp += keyToClipboardHandler_path_separator; // drop down menu for getting path to clipboard var pathToClipboard = (ToolStripMenuItem)NodeRightClickMenu.Items[2]; var pathToClipboard_Javascript = pathToClipboard.DropDownItems[0]; @@ -974,12 +1003,60 @@ private void Tree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) } ); pathToClipboard_RemesPath.MouseUp += pathToClipboardHandler_Remespath; - switch (Main.settings.key_style) + var pathToClipboard_path_separator = pathToClipboard.DropDownItems[3]; + pathToClipboard_path_separator.Text = $"Use path_separator setting ({Main.settings.path_separator})"; + if (pathToClipboardHandler_path_separator != null) + { + try + { + pathToClipboard_path_separator.MouseUp -= pathToClipboardHandler_path_separator; + } + catch { } + } + pathToClipboardHandler_path_separator = new MouseEventHandler( + (s2, e2) => + { + if (Main.pathSeparator == JNode.DEFAULT_PATH_SEPARATOR && !hasWarnedNo_path_separator) + { + MessageBox.Show($"You chose \"Path to clipboard\" with the \"Use path_separator setting\" option, but your path_separator is still the default {Main.settings.path_separator}. The {Main.settings.key_style} style is being used instead.", + "path_separator setting not configured", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + hasWarnedNo_path_separator = true; + } + Npp.TryCopyToClipboard(PathToTreeNode(node, Main.settings.key_style, Main.pathSeparator)); + } + ); + pathToClipboard_path_separator.MouseUp += pathToClipboardHandler_path_separator; + // shortcut to whatever the current settings say if user clicks on the parent item + if (pathToClipboardHandler != null) + pathToClipboard.MouseUp -= pathToClipboardHandler; + if (keyToClipboardHandler != null) + keyToClipboard.MouseUp -= keyToClipboardHandler; + if (Main.pathSeparator == JNode.DEFAULT_PATH_SEPARATOR) + { + switch (Main.settings.key_style) + { + case KeyStyle.RemesPath: + pathToClipboardHandler = pathToClipboardHandler_Remespath; + keyToClipboardHandler = keyToClipboardHandler_Remespath; + break; + case KeyStyle.Python: + pathToClipboardHandler = pathToClipboardHandler_Python; + keyToClipboardHandler = keyToClipboardHandler_Python; + break; + case KeyStyle.JavaScript: + pathToClipboardHandler = pathToClipboardHandler_Javascript; + keyToClipboardHandler = keyToClipboardHandler_Javascript; + break; + } + } + else { - case (KeyStyle.RemesPath): pathToClipboard.MouseUp += pathToClipboardHandler_Remespath; break; - case (KeyStyle.Python): pathToClipboard.MouseUp += pathToClipboardHandler_Python; break; - case (KeyStyle.JavaScript): pathToClipboard.MouseUp += pathToClipboardHandler_Javascript; break; + pathToClipboardHandler = pathToClipboardHandler_path_separator; + keyToClipboardHandler = keyToClipboardHandler_path_separator; } + pathToClipboard.MouseUp += pathToClipboardHandler; + keyToClipboard.MouseUp += keyToClipboardHandler; NodeRightClickMenu.Items[3].MouseUp -= ToggleSubtreesHandler; JNode nodeJson = pathsToJNodes[node.FullPath]; ToggleSubtreesHandler = new MouseEventHandler( @@ -1056,7 +1133,7 @@ private void Tree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) /// /// /// - public string PathToTreeNode(TreeNode node, KeyStyle style = KeyStyle.Python, List path = null) + public string PathToTreeNode(TreeNode node, KeyStyle style = KeyStyle.Python, char separator = JNode.DEFAULT_PATH_SEPARATOR, List path = null) { if (path == null) path = new List(); @@ -1067,17 +1144,14 @@ public string PathToTreeNode(TreeNode node, KeyStyle style = KeyStyle.Python, Li path.Reverse(); // cuz they were added from the node to the root return string.Join("", path); } - path.Add(KeyOfTreeNode(node, style)); - return PathToTreeNode(node.Parent, style, path); + path.Add(KeyOfTreeNode(node, style, separator)); + return PathToTreeNode(node.Parent, style, separator, path); } /// - /// See JNode.FormatKey, but uses the key of a TreeNode + /// See , but uses the key of a TreeNode as the first argument, and separator as the third argument. /// - /// - /// - /// - public string KeyOfTreeNode(TreeNode node, KeyStyle style) + public string KeyOfTreeNode(TreeNode node, KeyStyle style, char separator = JNode.DEFAULT_PATH_SEPARATOR) { if (node.Name == "" // TreeNodes representing array members have no name // but we need to be careful because an object could have the empty string as a key @@ -1088,9 +1162,18 @@ public string KeyOfTreeNode(TreeNode node, KeyStyle style) // one treenode for every i^th JNode in the JArray. string[] parts = node.Text.Split(' ', ':'); int idx = int.Parse(parts[0]); - return $"[{idx}]"; + return JNode.FormatIndex(idx, separator); + } + try + { + return JNode.FormatKey(node.Name, style, separator); + } + catch (Exception ex) + { + MessageBox.Show($"While attempting to format key {node.Name} using style, the following error occurred:\r\n{ex}", + "Error while validating JSON against schema", MessageBoxButtons.OK, MessageBoxIcon.Error); + return ""; } - return JNode.FormatKey(node.Name, style); } /// diff --git a/JsonToolsNppPlugin/Forms/TreeViewer.resx b/JsonToolsNppPlugin/Forms/TreeViewer.resx index b0cc4e7..d00950f 100644 --- a/JsonToolsNppPlugin/Forms/TreeViewer.resx +++ b/JsonToolsNppPlugin/Forms/TreeViewer.resx @@ -125,7 +125,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACw - DgAAAk1TRnQBSQFMAgEBDwEAAcgBAQHIAQEBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + DgAAAk1TRnQBSQFMAgEBDwEAAdABAQHQAQEBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAAUADAAEBAQABCAYAARAYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA @@ -157,9 +157,9 @@ AVcBFAFKAVcBShUUEAAUFAFQAXgBUAEUARIBVwF4ARMUFBAAAhQBbgN0ARIDdAEUAW4BdAESBhQBeAFX AxQBEgF4ARIUFBAAAhQB6gFzAZoBbgESAZoCbgEUAXQBcwGaBhQBeAFXAxQBEgF4ARIGFAESAesB6gET AeoBEgFtARIBFAESAesB6gIUEAADFAESAZoCFAGUAXMEFAGaAeoFFAF4AVcDFAETAXgBUAYUAf8B7QH/ - AfgB7wH0AfcB/wEUAf8BkgHyAhQQAAMUARIBmgMUAZoDFAFuAZoFFAFXAXgBSgQUAVABeAFQBRQB/wHs - AbwB+AHvAQcBFAH/AeoB/wQUEAADFAESAZoDFAJ0ARQBdAGaAXQFFAFQAXgBUAQUAlcBSgUUAeoB7wHz - AfgB7wEHARQB/wHqAf8EFBAAAhQBEwESAZoEFAGaAxQBmgYUAXgBVwMUARIBeAESBhQBBwETAfMB+AHv + AewB7wH0AfcB/wEUAf8BkgHyAhQQAAMUARIBmgMUAZoDFAFuAZoFFAFXAXgBSgQUAVABeAFQBRQB/wHs + AbwB7AHvAQcBFAH/AeoB/wQUEAADFAESAZoDFAJ0ARQBdAGaAXQFFAFQAXgBUAQUAlcBSgUUAeoB7wHz + AewB7wEHARQB/wHqAf8EFBAAAhQBEwESAZoEFAGaAxQBmgYUAXgBVwMUARIBeAESBhQBBwETAfMB7AHv Af8B6gH/ARQB/wHqAe8CFBAAAhQBcwF0AZoBFAESARMBbgGaARQBbQEUAZoGFAF4AVcDFAESAXgBEgYU AW0B8gHwARQB7wEHAfIB7QEUAW0B8gH3AhQQAAMUAXQBmgIUApoBbgEUAXQBmgF1BhQBVwF4AxQBSgF4 ARIKFAHvAQcIFBAAFBQBEwJ4ARMBUAF4AVcLFALvCBQQADAUEAAwFBAAMBQQAMUUAYsBsgGzARQCsgsU diff --git a/JsonToolsNppPlugin/JSONTools/JNode.cs b/JsonToolsNppPlugin/JSONTools/JNode.cs index 0f379d8..f15b876 100644 --- a/JsonToolsNppPlugin/JSONTools/JNode.cs +++ b/JsonToolsNppPlugin/JSONTools/JNode.cs @@ -825,7 +825,7 @@ public bool ParentHierarchyHelper(JNode root, JNode current, List keys, return false; } - private static readonly Regex DOT_COMPATIBLE_REGEX = new Regex("^[_a-zA-Z][_a-zA-Z\\d]*$"); + private static readonly Regex DOT_COMPATIBLE_REGEX = new Regex("^[_a-zA-Z][_a-zA-Z\\d]*$", RegexOptions.Compiled); // "dot compatible" means a string that starts with a letter or underscore // and contains only letters, underscores, and digits @@ -844,25 +844,22 @@ public bool ContainsPosition(int pos) return pos > position && pos <= position + utf8len; } + public const char DEFAULT_PATH_SEPARATOR = '\x01'; + /// /// Get the the path to the JNode that contains position pos in a UTF-8 encoded document.

- /// See PathToTreeNode for information on how paths are formatted. + /// See for information on how paths are formatted. ///
- /// - /// - /// - /// - /// - public string PathToPosition(int pos, KeyStyle style = KeyStyle.Python) + public string PathToPosition(int pos, KeyStyle style = KeyStyle.Python, char separator=DEFAULT_PATH_SEPARATOR) { - return PathToPositionHelper(pos, style, new List()); + return PathToPositionHelper(pos, style, new List(), separator); } - public string PathToPositionHelper(int pos, KeyStyle style, List path) + public string PathToPositionHelper(int pos, KeyStyle style, List path, char separator) { string result; if (ContainsPosition(pos)) - return FormatPath(path, style); + return FormatPath(path, style, separator); if (this is JArray arr) { if (arr.Length == 0) @@ -874,7 +871,7 @@ public string PathToPositionHelper(int pos, KeyStyle style, List path) } JNode child = arr[ii]; path.Add(ii); - result = child.PathToPositionHelper(pos, style, path); + result = child.PathToPositionHelper(pos, style, path, separator); if (result.Length > 0) return result; path.RemoveAt(path.Count - 1); @@ -884,7 +881,7 @@ public string PathToPositionHelper(int pos, KeyStyle style, List path) foreach (KeyValuePair kv in obj.children) { path.Add(kv.Key); - result = kv.Value.PathToPositionHelper(pos, style, path); + result = kv.Value.PathToPositionHelper(pos, style, path, separator); if (result.Length > 0) return result; path.RemoveAt(path.Count - 1); @@ -893,25 +890,36 @@ public string PathToPositionHelper(int pos, KeyStyle style, List path) return ""; } - private static string FormatPath(List path, KeyStyle style) + + private static string FormatPath(List path, KeyStyle style, char separator) { StringBuilder sb = new StringBuilder(); + bool usesSeparator = separator != DEFAULT_PATH_SEPARATOR; foreach (object member in path) { if (member is int ii) { - sb.Append($"[{ii}]"); + sb.Append(FormatIndex(ii, separator)); } else if (member is string key) { - sb.Append(FormatKey(key, style)); + sb.Append(FormatKey(key, style, separator)); } } return sb.ToString(); } /// - /// Get the key in square brackets or prefaced by a quote as determined by the style.

+ /// sep CANNOT be any of the characters in the following JSON string: "\"0123456789" + ///
+ public static void ThrowIfPathSeparatorInvalid(char sep) + { + if (sep == '"' || (sep >= '0' && sep <= '9')) + throw new ArgumentException("separator CANNOT be any of the characters in the following JSON string: \"\\\"0123456789\"", "separator"); + } + + /// + /// Get the key in square brackets or prefaced by a quote as determined by the style and separator (ignored if equal to )

/// Style: one of 'p' (Python), 'j' (JavaScript), or 'r' (RemesPath)

/// EXAMPLES (using the JSON {"a b": [1, {"c": 2}], "d": [4]}

/// Using key "a b'":

@@ -921,50 +929,60 @@ private static string FormatPath(List path, KeyStyle style) /// Using key "c":

/// - JavaScript style: .c

/// - RemesPath style: .c

- /// - Python style: ['c'] + /// - Python style: ['c']

+ /// Using key "a b" and separator '/', we get "/\"a b\""

+ /// Using key "a b" and separator 'b', we get "b\"a b\""

+ /// Using key "c" and separator 'c', we get "c\"c\""

+ /// Using key "c" and separator '/', we get "/c" /// /// /// /// /// - public static string FormatKey(string key, KeyStyle style = KeyStyle.Python) + public static string FormatKey(string key, KeyStyle style = KeyStyle.Python, char separator = DEFAULT_PATH_SEPARATOR) { + if (separator != DEFAULT_PATH_SEPARATOR) + { + ThrowIfPathSeparatorInvalid(separator); + return key.IndexOf(separator) < 0 && DOT_COMPATIBLE_REGEX.IsMatch(key) + ? $"{separator}{key}" + : $"{separator}{StrToString(key, true)}"; + } switch (style) { - case KeyStyle.RemesPath: - { - if (DOT_COMPATIBLE_REGEX.IsMatch(key)) - return $".{key}"; - string escapedKey = StrToString(key, false); - string keyDubquotesUnescaped = escapedKey.Replace("\\\"", "\"").Replace("`", "\\`"); - return $"[`{keyDubquotesUnescaped}`]"; - } - case KeyStyle.JavaScript: - { - if (DOT_COMPATIBLE_REGEX.IsMatch(key)) - return $".{key}"; - string escapedKey = StrToString(key, false); - if (key.Contains('\'')) - { - return $"[\"{escapedKey}\"]"; - } - string keyDubquotesUnescaped = escapedKey.Replace("\\\"", "\""); - return $"['{keyDubquotesUnescaped}']"; - } - case KeyStyle.Python: - { - string escapedKey = StrToString(key, false); - if (escapedKey.Contains('\'')) - { - return $"[\"{escapedKey}\"]"; - } - string keyDubquotesUnescaped = escapedKey.Replace("\\\"", "\""); - return $"['{keyDubquotesUnescaped}']"; - } - default: throw new ArgumentException("style argument for PathToTreeNode must be a KeyStyle member"); + case KeyStyle.RemesPath: + if (DOT_COMPATIBLE_REGEX.IsMatch(key)) + return $".{key}"; + string escapedKey = StrToString(key, false); + string keyDubquotesUnescaped = escapedKey.Replace("\\\"", "\"").Replace("`", "\\`"); + return $"[`{keyDubquotesUnescaped}`]"; + case KeyStyle.JavaScript: + if (DOT_COMPATIBLE_REGEX.IsMatch(key)) + return $".{key}"; + escapedKey = StrToString(key, false); + if (key.Contains('\'')) + { + return $"[\"{escapedKey}\"]"; + } + keyDubquotesUnescaped = escapedKey.Replace("\\\"", "\""); + return $"['{keyDubquotesUnescaped}']"; + case KeyStyle.Python: + escapedKey = StrToString(key, false); + if (escapedKey.Contains('\'')) + { + return $"[\"{escapedKey}\"]"; + } + keyDubquotesUnescaped = escapedKey.Replace("\\\"", "\""); + return $"['{keyDubquotesUnescaped}']"; + default: throw new ArgumentException("style argument for FormatKey must be a KeyStyle member", "style"); } } + public static string FormatIndex(int idx, char separator) + { + return separator == DEFAULT_PATH_SEPARATOR ? $"[{idx}]" : $"{separator}{idx}"; + } + public static Dictionary DtypeStrings = new Dictionary { [Dtype.SCALAR] = "scalar", @@ -979,9 +997,7 @@ public static string FormatKey(string key, KeyStyle style = KeyStyle.Python) [Dtype.STR] = "string", [Dtype.UNKNOWN] = "unknown", [Dtype.SLICE] = "slice", - //[Dtype.DATE] = "date", [Dtype.REGEX] = "regex", - //[Dtype.DATETIME] = "datetime", }; /// diff --git a/JsonToolsNppPlugin/Main.cs b/JsonToolsNppPlugin/Main.cs index 81e9793..0bcb7cb 100644 --- a/JsonToolsNppPlugin/Main.cs +++ b/JsonToolsNppPlugin/Main.cs @@ -76,11 +76,11 @@ class Main private static System.Threading.Timer parseTimer = new System.Threading.Timer(DelayedParseAfterEditing, new System.Threading.AutoResetEvent(true), 1000, 1000); private static readonly string[] fileExtensionsToAutoParse = new string[] { "json", "jsonc", "jsonl", "json5" }; private static bool bufferFinishedOpening = false; - ///// - ///// this form is always created on the main thread, so mainThreadForm.Invoke(X) could be a way to call X on the main thread.

- ///// I am not using this approach at present because it appears to have a noticeable (and annoying) impact on Notepad++ startup. - /////
- //public static Form mainThreadForm; + + /// + /// this is set from + /// + public static char pathSeparator = SetPathSeparatorFromSettings(); // toolbar icons static Icon dockingFormIcon = null; // indicators (used for selection remembering) @@ -1160,10 +1160,13 @@ static void OpenSettings() { bool oldUseNppStyling = settings.use_npp_styling; float oldTreeViewFontSize = settings.tree_view_font_size; + string oldPathSepStr = settings.path_separator; settings.ShowDialog(); millisecondsAfterLastEditToParse = (settings.inactivity_seconds_before_parse < 1) ? 1000 : 1000 * settings.inactivity_seconds_before_parse; + if (settings.path_separator != oldPathSepStr) + pathSeparator = SetPathSeparatorFromSettings(oldPathSepStr); // make sure grepperForm gets these new settings as well if (grepperForm != null && !grepperForm.IsDisposed) { @@ -1173,6 +1176,29 @@ static void OpenSettings() RestyleEverything(); } + private static char SetPathSeparatorFromSettings(string oldPathSepStr = "\"\\u0001\"") + { + string newPathSepStr; + char newPathSepChar; + try + { + newPathSepStr = (string)new JsonParser().ParseString(settings.path_separator).value; + if (newPathSepStr.Length != 1) + throw new Exception("path_separator setting must be a JSON string containing exactly one character"); + newPathSepChar = newPathSepStr[0]; + JNode.ThrowIfPathSeparatorInvalid(newPathSepChar); + } + catch (Exception ex) + { + MessageBox.Show($"path_separator setting could not be changed from {oldPathSepStr} to {settings.path_separator} due to the following error:\r\n{ex}", + "Could not change path_separator setting", MessageBoxButtons.OK, MessageBoxIcon.Error); + settings.path_separator = oldPathSepStr; + newPathSepChar = pathSeparator; + settings.SaveToIniFile(); + } + return newPathSepChar; + } + /// /// having a global shared JsonParser is an obvious risk factor for race conditions, so having this method is preferable /// @@ -1311,7 +1337,7 @@ private static void RefreshErrorFormInOwnThread(string fname) public static void CopyPathToCurrentPosition() { int pos = Npp.editor.GetCurrentPos(); - string result = PathToPosition(settings.key_style, pos); + string result = PathToPosition(settings.key_style, pathSeparator, pos); if (result.Length == 0) { MessageBox.Show($"Did not find a node at position {pos} of this file", @@ -1329,7 +1355,7 @@ public static void CopyPathToCurrentPosition() ///
/// /// - private static string PathToPosition(KeyStyle style, int pos = -1) + private static string PathToPosition(KeyStyle style, char separator, int pos = -1) { if (pos == -1) pos = Npp.editor.GetCurrentPos(); @@ -1359,25 +1385,34 @@ private static string PathToPosition(KeyStyle style, int pos = -1) if (parserState == ParserState.FATAL || json == null) return ""; } - if (usesSelections) + try { - // check if pos is inside a selection - // re-parse this remembered selection - // (we can't rely on the position-json mapping of the selection-remembering object being in sync with the document) - (int start, int end) = SelectionManager.GetEnclosingRememberedSelection(pos, selectionRememberingIndicator1, selectionRememberingIndicator2); - if (start < 0) - return ""; - string selText = Npp.GetSlice(start, end); - var parser = JsonParserFromSettings(); - JNode selJson = parser.Parse(selText); - if (parser.fatal) - return ""; - // this remembered selection still contains JSON, so find the path to this position in it - string formattedKey = JNode.FormatKey($"{start},{end}", style); - return formattedKey + selJson.PathToPosition(pos - start, style); + if (usesSelections) + { + // check if pos is inside a selection + // re-parse this remembered selection + // (we can't rely on the position-json mapping of the selection-remembering object being in sync with the document) + (int start, int end) = SelectionManager.GetEnclosingRememberedSelection(pos, selectionRememberingIndicator1, selectionRememberingIndicator2); + if (start < 0) + return ""; + string selText = Npp.GetSlice(start, end); + var parser = JsonParserFromSettings(); + JNode selJson = parser.Parse(selText); + if (parser.fatal) + return ""; + // this remembered selection still contains JSON, so find the path to this position in it + string formattedKey = JNode.FormatKey($"{start},{end}", style, separator); + return formattedKey + selJson.PathToPosition(pos - start, style, separator); + } + else + return json.PathToPosition(pos, style, separator); + } + catch (Exception ex) + { + MessageBox.Show($"While attempting to format the path to the current position, the following error occurred:\r\n{ex}", + "Error while validating JSON against schema", MessageBoxButtons.OK, MessageBoxIcon.Error); + return ""; } - else - return json.PathToPosition(pos, style); } /// @@ -1839,7 +1874,7 @@ public static void OpenSortForm() { if (sortForm == null || sortForm.IsDisposed) sortForm = new SortForm(); - sortForm.PathTextBox.Text = PathToPosition(KeyStyle.RemesPath); + sortForm.PathTextBox.Text = PathToPosition(KeyStyle.RemesPath, JNode.DEFAULT_PATH_SEPARATOR); sortForm.Show(); sortForm.Focus(); } diff --git a/JsonToolsNppPlugin/PluginInfrastructure/SettingsBase.cs b/JsonToolsNppPlugin/PluginInfrastructure/SettingsBase.cs index c6f01c9..af0a1f5 100644 --- a/JsonToolsNppPlugin/PluginInfrastructure/SettingsBase.cs +++ b/JsonToolsNppPlugin/PluginInfrastructure/SettingsBase.cs @@ -284,7 +284,19 @@ public void ShowDialog(bool debug = false) var oldValue = propertyInfo.GetValue(this, null); var newValue = propertyInfo.GetValue(copy, null); if (!oldValue.Equals(newValue)) - propertyInfo.SetValue(this, newValue, null); + { + try + { + propertyInfo.SetValue(this, newValue, null); + } + catch (Exception ex) + { + MessageBox.Show($"Could not change setting {propertyInfo.Name} to value {newValue}, so it will remain set as {oldValue}.\r\n" + + $"Got the following exception:\r\n{ex}", + $"Invalid value for setting {propertyInfo.Name}", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } } dialog.Close(); }; diff --git a/JsonToolsNppPlugin/Properties/AssemblyInfo.cs b/JsonToolsNppPlugin/Properties/AssemblyInfo.cs index d112aca..ae4df1b 100644 --- a/JsonToolsNppPlugin/Properties/AssemblyInfo.cs +++ b/JsonToolsNppPlugin/Properties/AssemblyInfo.cs @@ -28,5 +28,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion("8.0.0.6")] -[assembly: AssemblyFileVersion("8.0.0.6")] +[assembly: AssemblyVersion("8.0.0.7")] +[assembly: AssemblyFileVersion("8.0.0.7")] diff --git a/JsonToolsNppPlugin/Tests/FormatPathTests.cs b/JsonToolsNppPlugin/Tests/FormatPathTests.cs index 8ac6d9e..80c2ea4 100644 --- a/JsonToolsNppPlugin/Tests/FormatPathTests.cs +++ b/JsonToolsNppPlugin/Tests/FormatPathTests.cs @@ -9,7 +9,7 @@ public class FormatPathTester public static bool Test() { JsonParser parser = new JsonParser(); - JNode json = parser.Parse("{\"a\":1,\"b \":\"f\",\"cu\":[false,true,[{\"\":{\"bufrear\":null}}]],\"d'\":-1.5,\"b\\\\e\\\"\\r\\n\\t`\":[NaN,Infinity,-Infinity]}"); + JNode json = parser.Parse("{\"a\":1,\"b \":\"f\",\"cu\":[false,true,[{\"\":{\"bufrear\":null}}]],\"d'\":-1.5,\"b\\\\e\\\"\\r\\n\\t`\":[NaN,Infinity,-Infinity], \"e\\\"'\": \"bar\"}"); var testcases = new (int pos, KeyStyle style, string correctPath)[] { (6, KeyStyle.JavaScript, ".a"), @@ -36,6 +36,9 @@ public static bool Test() (93, KeyStyle.JavaScript, "['b\\\\e\"\\r\\n\\t`'][1]"), (93, KeyStyle.RemesPath, "[`b\\\\e\"\\r\\n\\t\\``][1]"), (93, KeyStyle.Python, "['b\\\\e\"\\r\\n\\t`'][1]"), + (121, KeyStyle.JavaScript, "[\"e\\\"'\"]"), + (121, KeyStyle.RemesPath, "[`e\"'`]"), + (121, KeyStyle.Python, "[\"e\\\"'\"]"), }; int ii = 0; int testsFailed = 0; @@ -59,18 +62,51 @@ public static bool Test() Npp.AddLine($"Got the path to position {pos} ({style} style) as {path}, but it should be {correctPath}"); } } + + string separatorTestJsonStr = "{\"foo\": [12, {\"ba/r\": \"a\", \"baz\\\"\": null, \"12\": true}], \"baz\": {\"01\": false, \"a b\": null}, \"_f\": [-10,0.25]}"; + JNode separatorTestJson = parser.Parse(separatorTestJsonStr); + + var separatorTestcases = new (int pos, char separator, string correctPath)[] + { + (8, '/', "/foo"), + (8, ' ', " foo"), + (10, '/', "/foo/0"), + (23, '\\', "\\foo\\1\\\"ba/r\""), + (24, '\\', "\\foo\\1\\\"ba/r\""), + (39, '$', "$foo$1$\"baz\\\"\""), + (49, 'f', "f\"foo\"f1f\"12\""), + (75, 'z', "z\"baz\"z\"01\""), + (75, '/', "/baz/\"01\""), + (84, '/', "/baz/\"a b\""), + (88, ' ', " baz \"a b\""), + (100, '/', "/_f/0"), + (104, '_', "_\"_f\"_1"), + }; + + foreach ((int pos, char separator, string correctPath) in separatorTestcases) + { + ii++; + string path; + try + { + path = separatorTestJson.PathToPosition(pos, KeyStyle.JavaScript, separator); + } + catch (Exception ex) + { + testsFailed++; + Npp.AddLine($"While trying to get the path to position {pos} (Separator style, separator \"{separator}\"), threw exception\r\n{ex}"); + continue; + } + if (path != correctPath) + { + testsFailed++; + Npp.AddLine($"Got the path to position {pos} (Separator style, separator \"{separator}\") as {path}, but it should be {correctPath}"); + } + } + Npp.AddLine($"Failed {testsFailed} tests."); Npp.AddLine($"Passed {ii - testsFailed} tests."); return testsFailed > 0; } - - //public void TestPathToTreeNode() - //{ - // TreeNode root = new TreeNode(); - // TreeView tree = new TreeView(); - // var pathsToJNodes = new Dictionary(); - // TreeViewer.JsonTreePopulateHelper_DirectChildren(tree, root, json, pathsToJNodes); - // var testcases = new () - //} } } diff --git a/JsonToolsNppPlugin/Tests/UserInterfaceTests.cs b/JsonToolsNppPlugin/Tests/UserInterfaceTests.cs index c6027fc..804d8c6 100644 --- a/JsonToolsNppPlugin/Tests/UserInterfaceTests.cs +++ b/JsonToolsNppPlugin/Tests/UserInterfaceTests.cs @@ -793,6 +793,8 @@ public static bool Test() bool previousRememberComments = Main.settings.remember_comments; bool previousHasWarnedSelectionsForgotten = Main.hasWarnedSelectionsForgotten; bool previousOfferToShowLint = Main.settings.offer_to_show_lint; + KeyStyle previousKeyStyle = Main.settings.key_style; + string previousPathSeparator = Main.settings.path_separator; // remember what the user's clipboard was before tests start, because the tests hijack the clipboard and that's not nice string clipboardValueBeforeTests = Clipboard.GetText(); // require these settings for the UI tests alone @@ -804,6 +806,8 @@ public static bool Test() Main.settings.minimal_whitespace_compression = true; Main.settings.remember_comments = false; Main.settings.offer_to_show_lint = false; + Main.settings.path_separator = "\"\\u0001\""; + Main.settings.key_style = KeyStyle.RemesPath; // if this is false, a message-box will pop up at some point. // this message box doesn't block the main thread, but it introduces some asynchronous behavior // that was probably responsible for crashing the UI tests @@ -867,6 +871,8 @@ public static bool Test() Main.settings.remember_comments = previousRememberComments; Main.hasWarnedSelectionsForgotten = previousHasWarnedSelectionsForgotten; Main.settings.offer_to_show_lint = previousOfferToShowLint; + Main.settings.key_style = previousKeyStyle; + Main.settings.path_separator = previousPathSeparator; // if the user's clipboard is still set to whatever we most recently hijacked it with, reset it to whatever it was before the tests // this won't work if their clipboard contained non-text data beforehand, but it's better than nothing if (Clipboard.GetText() == lastClipboardValue && !(clipboardValueBeforeTests is null) && clipboardValueBeforeTests.Length > 0) diff --git a/JsonToolsNppPlugin/Utils/Settings.cs b/JsonToolsNppPlugin/Utils/Settings.cs index 1bac2ac..c0fbd74 100644 --- a/JsonToolsNppPlugin/Utils/Settings.cs +++ b/JsonToolsNppPlugin/Utils/Settings.cs @@ -114,10 +114,14 @@ public class Settings : SettingsBase #endregion #region MISCELLANEOUS - [Description("The style of key to use when getting the path or key/index of a node or line"), + [Description("The style of key to use when getting the path or key/index of a node or line.\r\nSee the documentation (https://github.com/molsonkiko/JsonToolsNppPlugin/blob/main/docs/README.md#key_style-setting) for an explanation of each type.\r\nThis setting is IGNORED when path_separator is NOT the default \"\\u0001\"."), Category("Miscellaneous"), DefaultValue(KeyStyle.RemesPath)] public KeyStyle key_style { get; set; } + [Description("The separator to use when formatting a path. This setting is IGNORED when it is set to \"\\u0001\" (the default).\r\nThis MUST have exactly one character, which CANNOT be any of the characters in the following JSON string: \"\\\"0123456789\"\r\nThe algorithm for formatting an object key or array index is as follows:\r\n===========\r\nif the key is an array index:\r\n format it as plaintext (for example, index 10 becomes \"$10\" if \"$\" was the path_separator)\r\nif the key contains the path_separator:\r\n format it as a JSON string (for example, key \"foo\" would be formatted as \"/foo\" if \"/\" was the path_separator)\r\nelse if the key starts with (_ or a-z or A-Z) and all its other characters are (_ or 0-9 or a-z or A-Z):\r\n format it as plain text (for example, key \"_foo\" becomes \"/_foo\" if \"/\" was the path_separator, but \"_\\\"_foo\\\"\" if \"_\" was the path_separator)\r\nelse:\r\n format it as a JSON string (for example, the key \"a b\" would be formatted as \"/\\\"a b\\\"\" if the path_separator was \"/\" even though it doesn't contain the path_separator)"), + Category("Miscellaneous"), DefaultValue("\"\\u0001\"")] + public string path_separator { get; set; } + [Description("When selecting every JSON in the file, start trying to parse only at these characters.\r\n" + "Only JSON valid according to the NAN_INF logger_level is tolerated.\r\n" + "Example: if \"[{ are chosen (default), we consider only potential strings, arrays, and objects.\r\n" + diff --git a/docs/README.md b/docs/README.md index 48ac654..adefe9d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -258,7 +258,7 @@ Beginning in [v7.0](/CHANGELOG.md#700---2024-02-09), this automatic validation w *Added in version v5.0.0* -The `Path to current position` menu option lets you fill the clipboard with the path to the current position in the document. +The `Path to current position` menu option lets you fill the clipboard with the path to the current position in the document. The path is formatted according to the [`key_style` and `path_separator` settings](#key_style-and-path_separator-settings), described below. This replaced the old `Path to current line` menu option. @@ -275,13 +275,25 @@ The `Path to current line` menu option lets you fill the clipboard with the path ![Getting the path to current line](/docs/path%20to%20current%20line.PNG) -### Key style ### +### `key_style` and `path_separator` settings ### + +If you are using JsonTools [v8](/CHANGELOG.md#800---2024-06-29) or older, you can ignore the below discussion of the `path_separator` setting, as it was added in [v8.1](/CHANGELOG.md#810---unreleased-yyyy-mm-dd). + +The `key_style` and `path_separator` settings control the formatting of the `Path to current position` command. + +The `key_style` setting has the following options. `RemesPath` style is the default. +- `RemesPath` style (dot syntax and backtick-quoted strings) +- `JavaScript` style (dot syntax and C-style quoted strings in square brackets) +- `Python` style (C-style quoted strings in square brackets) + +If you prefer for keys and indices to be separated by a custom character, use the `path_separator` setting. __`path_separator` ignored when it is set to the default `"\u0001"`; otherwise `key_style` is ignored.__ The `path_separator` character *cannot* be any of the characters in the following JSON string: `"\"0123456789"`. -By default, the path clipped is in RemesPath style (dot syntax and backtick-quoted strings). You can get JavaScript style (dot syntax and c-style quoted strings in square brackets) or Python style (c-style quoted strings in square brackets) in the settings. For example, the different path styles might look like this: -- Remespath (default): ``[`a b`][0].c`` -- Python: `['a b'][0]['c']` -- JavaScript: `['a b'][0].c` +- `Remespath` (default): ``[`a b`][0].c`` +- `Python`: `['a b'][0]['c']` +- `JavaScript`: `['a b'][0].c` +- `path_separator` set to `/`: `/"a b"/0/c` (the `"a b"` key is in quotes because it does not match the regular expression `^[_a-zA-Z][_a-zA-Z\d]*$`) +- `path_separator` set to `c`: `c"a b"c0c"c"` (the `"c"` key is also in quotes because it contains the `path_separator`) ## RemesPath ## @@ -392,8 +404,8 @@ The `View all subtrees` checkbox on the JSON viewer form allows you to quickly t You can right click on a tree node to copy any of the following to the clipboard: * Value -* Key/index (customizable via [key style](#key-style)) -* Path (see [key style](#key-style)) +* Key/index (see the [the `key_style` and `path_separator` settings](#key_style-and-path_separator-settings)) +* Path (see the `key_style` and `path_separator` settings) In versions 3.4.0 through 3.6.1.1, you can also click on the `Current path` button beneath the tree to copy the path of the currently selected tree node to the clipboard. The path will have the style of whatever default style you chose in the settings (shown in the adjacent text box). In versions 3.7.0 and above, this button does not exist, so just select and copy the text in the box. diff --git a/most recent errors.txt b/most recent errors.txt index 0a63b9b..92be79e 100644 --- a/most recent errors.txt +++ b/most recent errors.txt @@ -1,4 +1,4 @@ -Test results for JsonTools v8.0.0.6 on Notepad++ 8.6.4 64bit +Test results for JsonTools v8.0.0.7 on Notepad++ 8.6.4 64bit NOTE: Ctrl-F (regular expressions *on*) for "Failed [1-9]\d*" to find all failed tests Tests failed: YAML dumper ========================= @@ -182,7 +182,7 @@ Testing JNode PathToPosition method ========================= Failed 0 tests. -Passed 24 tests. +Passed 40 tests. ========================= Testing INI file parser ========================= @@ -201,33 +201,33 @@ 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,744 +/- 1,835 ms over 32 trials -Load times (ms): 2, 1, 1, 5, 1, 1, 1, 4, 2, 1, 6, 1, 1, 2, 4, 1, 1, 6, 1, 1, 1, 4, 1, 1, 6, 1, 1, 1, 4, 1, 1, 6 +To convert JSON string of size 89556 into JNode took 4.73 +/- 3.64 ms over 32 trials +Load times (ms): 4, 3, 4, 11, 19, 2, 3, 7, 2, 2, 8, 2, 2, 3, 7, 2, 2, 2, 7, 2, 2, 7, 2, 2, 2, 7, 2, 2, 8, 2, 2, 2 ========================= Performance tests for RemesPath (float arithmetic) ========================= -Compiling query "@[@[:].a * @[:].t < @[:].e]" took 0,064 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,028 +/- 0,014 ms over 40 trials -Query times (ms): 0.089, 0.03, 0.06, 0.024, 0.035, 0.023, 0.051, 0.025, 0.024, 0.023, 0.022, 0.023, 0.022, 0.023, 0.022, 0.023, 0.023, 0.022, 0.022, 0.024, 0.022, 0.023, 0.023, 0.022, 0.022, 0.023, 0.023, 0.022, 0.022, 0.022, 0.023, 0.024, 0.023, 0.028, 0.063, 0.024, 0.023, 0.025, 0.025, 0.023 +Compiling query "@[@[:].a * @[:].t < @[:].e]" took 0.203 ms the first time, including approximately 0.103 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.012 ms over 40 trials +Query times (ms): 0.102, 0.07, 0.04, 0.04, 0.039, 0.039, 0.039, 0.055, 0.04, 0.036, 0.037, 0.039, 0.043, 0.056, 0.038, 0.042, 0.044, 0.046, 0.047, 0.058, 0.038, 0.039, 0.039, 0.038, 0.042, 0.057, 0.039, 0.038, 0.037, 0.039, 0.037, 0.056, 0.038, 0.037, 0.038, 0.038, 0.04, 0.059, 0.042, 0.052 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,055 ms the first time, including approximately 0,063 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,059 +/- 0,013 ms over 40 trials -Query times (ms): 0.126, 0.058, 0.057, 0.056, 0.055, 0.055, 0.058, 0.057, 0.06, 0.084, 0.085, 0.057, 0.054, 0.055, 0.07, 0.055, 0.054, 0.055, 0.054, 0.055, 0.055, 0.053, 0.054, 0.054, 0.054, 0.055, 0.054, 0.054, 0.055, 0.053, 0.066, 0.053, 0.054, 0.055, 0.055, 0.055, 0.054, 0.055, 0.054, 0.055 +Compiling query "@[@[:].z =~ `(?i)[a-z]{5}`]" took 0.059 ms the first time, including approximately 0.063 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.105 +/- 0.016 ms over 40 trials +Query times (ms): 0.183, 0.158, 0.107, 0.105, 0.108, 0.11, 0.101, 0.1, 0.104, 0.111, 0.098, 0.094, 0.111, 0.107, 0.105, 0.103, 0.101, 0.104, 0.105, 0.106, 0.091, 0.098, 0.102, 0.105, 0.115, 0.106, 0.096, 0.094, 0.096, 0.095, 0.099, 0.104, 0.095, 0.095, 0.1, 0.099, 0.102, 0.098, 0.098, 0.098 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,18 ms the first time, including approximately 0,199 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.251 ms the first time, including approximately 0.232 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,022 +/- 0,034 ms over 40 trials -Query times (ms): 0.081, 0.223, 0.019, 0.016, 0.015, 0.016, 0.015, 0.016, 0.015, 0.015, 0.015, 0.015, 0.016, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.016, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.015, 0.016, 0.015, 0.015, 0.015, 0.016 +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.044 +/- 0.055 ms over 40 trials +Query times (ms): 0.128, 0.045, 0.03, 0.047, 0.034, 0.373, 0.041, 0.03, 0.026, 0.028, 0.027, 0.029, 0.029, 0.029, 0.028, 0.027, 0.029, 0.03, 0.029, 0.031, 0.034, 0.03, 0.045, 0.033, 0.029, 0.033, 0.029, 0.031, 0.035, 0.036, 0.034, 0.033, 0.037, 0.035, 0.036, 0.036, 0.035, 0.037, 0.035, 0.034 Preview of result: "when q=false, nmax= 9830935647.0" ... ========================= @@ -266,11 +266,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,089 ms the first time, including approximately 0,074 ms to tokenize the query. Subsequent executions are effectively free due to caching. +@[:]->at(@, X)->at(@, onetwo)" took 0.137 ms the first time, including approximately 0.139 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,005 ms over 40 trials -Query times (ms): 0.045, 0.013, 0.012, 0.012, 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.013, 0.012, 0.013, 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.012, 0.012 +@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.027 +/- 0.011 ms over 40 trials +Query times (ms): 0.087, 0.029, 0.024, 0.026, 0.028, 0.023, 0.026, 0.027, 0.024, 0.051, 0.023, 0.025, 0.023, 0.025, 0.023, 0.026, 0.025, 0.026, 0.024, 0.025, 0.024, 0.024, 0.025, 0.026, 0.025, 0.026, 0.026, 0.025, 0.024, 0.021, 0.024, 0.024, 0.027, 0.026, 0.025, 0.027, 0.027, 0.026, 0.025, 0.025 Preview of result: [[1695727848, 0.287562638736685], [2126430375, 0.00767794129708177], [5310550656, 0.380769772645687], [2519183283, 0.153176220930558], [6610062385, 0.662996225870666], [987168256, 0.924410189999928], [6615003609, 0.917112691225947], [4465232046, 0.684311931851536], [8654414565, 0.631485392105992], [ ... ========================= @@ -279,29 +279,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,144 ms the first time, including approximately 0,126 ms to tokenize the query. Subsequent executions are effectively free due to caching. +@[:]->at(@, X)->at(@, onetwo)" took 0.145 ms the first time, including approximately 0.147 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,022 +/- 0,032 ms over 40 trials -Query times (ms): 0.052, 0.016, 0.017, 0.016, 0.015, 0.016, 0.016, 0.015, 0.016, 0.016, 0.016, 0.016, 0.016, 0.015, 0.016, 0.016, 0.016, 0.016, 0.016, 0.015, 0.016, 0.016, 0.015, 0.016, 0.016, 0.015, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.016, 0.015, 0.016, 0.016, 0.016, 0.027, 0.217 +@[:]->at(@, X)->at(@, onetwo)" on JNode from JSON of size 89556 into took 0.036 +/- 0.012 ms over 40 trials +Query times (ms): 0.104, 0.042, 0.045, 0.033, 0.054, 0.032, 0.029, 0.036, 0.033, 0.032, 0.033, 0.033, 0.029, 0.034, 0.034, 0.03, 0.032, 0.03, 0.034, 0.032, 0.033, 0.053, 0.032, 0.031, 0.031, 0.035, 0.033, 0.03, 0.035, 0.039, 0.036, 0.037, 0.036, 0.036, 0.033, 0.035, 0.031, 0.032, 0.031, 0.032 Preview of result: [[1695727848, 0.287562638736685], [2126430375, 0.00767794129708177], [5310550656, 0.380769772645687], [2519183283, 0.153176220930558], [6610062385, 0.662996225870666], [987168256, 0.924410189999928], [6615003609, 0.917112691225947], [4465232046, 0.684311931851536], [8654414565, 0.631485392105992], [ ... ========================= Performance tests for RemesPath (simple string mutations) ========================= -Compiling query "@[:].z = s_sub(@, g, B)" took 0,046 ms the first time, including approximately 0,058 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,014 +/- 0,005 ms over 40 trials -Query times (ms): 0.027, 0.012, 0.012, 0.011, 0.016, 0.014, 0.014, 0.013, 0.014, 0.025, 0.015, 0.014, 0.013, 0.014, 0.016, 0.014, 0.014, 0.013, 0.032, 0.021, 0.013, 0.011, 0.01, 0.011, 0.011, 0.01, 0.011, 0.01, 0.01, 0.012, 0.01, 0.019, 0.014, 0.011, 0.011, 0.012, 0.011, 0.011, 0.011, 0.01 +Compiling query "@[:].z = s_sub(@, g, B)" took 0.46 ms the first time, including approximately 0.096 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.037 +/- 0.007 ms over 40 trials +Query times (ms): 0.045, 0.04, 0.038, 0.028, 0.054, 0.038, 0.044, 0.046, 0.041, 0.041, 0.042, 0.043, 0.038, 0.049, 0.042, 0.042, 0.038, 0.044, 0.047, 0.041, 0.033, 0.031, 0.028, 0.03, 0.027, 0.036, 0.03, 0.017, 0.031, 0.033, 0.032, 0.046, 0.038, 0.032, 0.026, 0.032, 0.034, 0.04, 0.037, 0.031 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,092 ms the first time, including approximately 0,089 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,033 +/- 0,012 ms over 40 trials -Query times (ms): 0.066, 0.043, 0.036, 0.038, 0.031, 0.042, 0.025, 0.023, 0.024, 0.026, 0.027, 0.022, 0.021, 0.042, 0.047, 0.049, 0.043, 0.042, 0.035, 0.038, 0.031, 0.033, 0.041, 0.021, 0.064, 0.022, 0.019, 0.019, 0.019, 0.025, 0.028, 0.022, 0.025, 0.021, 0.022, 0.027, 0.039, 0.048, 0.04, 0.034 +Compiling query "@[:].x = ifelse(@ < 0.5, @ + 3, @ - 3)" took 0.096 ms the first time, including approximately 0.103 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.051 +/- 0.008 ms over 40 trials +Query times (ms): 0.06, 0.064, 0.073, 0.061, 0.052, 0.044, 0.048, 0.053, 0.046, 0.046, 0.042, 0.046, 0.043, 0.052, 0.044, 0.046, 0.047, 0.065, 0.05, 0.072, 0.05, 0.048, 0.045, 0.053, 0.054, 0.051, 0.047, 0.043, 0.037, 0.061, 0.058, 0.054, 0.049, 0.048, 0.043, 0.03, 0.047, 0.052, 0.05, 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" ... ========================= @@ -311,12 +311,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,151 ms the first time, including approximately 0,134 ms to tokenize the query. Subsequent executions are effectively free due to caching. +end for;" took 0.236 ms the first time, including approximately 0.199 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,07 +/- 0,161 ms over 40 trials -Query times (ms): 0.081, 1.073, 0.039, 0.039, 0.038, 0.036, 0.038, 0.037, 0.04, 0.037, 0.037, 0.037, 0.038, 0.036, 0.044, 0.036, 0.04, 0.038, 0.036, 0.037, 0.044, 0.039, 0.038, 0.07, 0.039, 0.039, 0.044, 0.036, 0.036, 0.05, 0.058, 0.034, 0.034, 0.034, 0.051, 0.05, 0.097, 0.07, 0.061, 0.047 +end for;" on JNode from JSON of size 89556 into took 0.092 +/- 0.014 ms over 40 trials +Query times (ms): 0.112, 0.088, 0.102, 0.084, 0.092, 0.093, 0.092, 0.092, 0.116, 0.122, 0.091, 0.09, 0.096, 0.093, 0.082, 0.093, 0.093, 0.125, 0.081, 0.104, 0.128, 0.107, 0.083, 0.086, 0.084, 0.08, 0.092, 0.081, 0.081, 0.086, 0.092, 0.089, 0.106, 0.086, 0.08, 0.078, 0.068, 0.068, 0.076, 0.086 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 ... ========================= @@ -325,18 +325,18 @@ 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 3,88 +/- 0,477 ms over 64 trials (minimal whitespace, sortKeys=TRUE) -To compress JNode from JSON string of 89556 took 2,03 +/- 0,255 ms over 64 trials (minimal whitespace, sortKeys=FALSE) -To Google-style pretty-print JNode from JSON string of 89556 took 4,268 +/- 0,533 ms over 64 trials (sortKeys=true, indent=4) -To Whitesmith-style pretty-print JNode from JSON string of 89556 took 4,256 +/- 0,339 ms over 64 trials (sortKeys=true, indent=4) -To PPrint-style pretty-print JNode from JSON string of 89556 took 5,87 +/- 0,313 ms over 64 trials (sortKeys=true, indent=4) +To compress JNode from JSON string of 89556 took 5.909 +/- 0.863 ms over 64 trials (minimal whitespace, sortKeys=TRUE) +To compress JNode from JSON string of 89556 took 3.727 +/- 0.972 ms over 64 trials (minimal whitespace, sortKeys=FALSE) +To Google-style pretty-print JNode from JSON string of 89556 took 6.326 +/- 1.453 ms over 64 trials (sortKeys=true, indent=4) +To Whitesmith-style pretty-print JNode from JSON string of 89556 took 6.328 +/- 1.081 ms over 64 trials (sortKeys=true, indent=4) +To PPrint-style pretty-print JNode from JSON string of 89556 took 7.013 +/- 1.122 ms over 64 trials (sortKeys=true, indent=4) ========================= Testing performance of JsonSchemaValidator and random JSON creation ========================= -To create a random set of tweet JSON of size 187855 (15 tweets) based on the matching schema took 6,751 +/- 3,211 ms over 64 trials -To compile the tweet schema to a validation function took 0,483 +/- 1,051 ms over 64 trials -To validate tweet JSON of size 187855 (15 tweets) based on the compiled schema took 1,12 +/- 0,264 ms over 64 trials +To create a random set of tweet JSON of size 184139 (15 tweets) based on the matching schema took 7.631 +/- 3.538 ms over 64 trials +To compile the tweet schema to a validation function took 0.452 +/- 0.86 ms over 64 trials +To validate tweet JSON of size 184139 (15 tweets) based on the compiled schema took 1.259 +/- 0.358 ms over 64 trials ========================= Testing JSON grepper's API request tool ========================= diff --git a/translation/english.json5 b/translation/english.json5 index 3517d1a..3e747ab 100644 --- a/translation/english.json5 +++ b/translation/english.json5 @@ -235,7 +235,8 @@ "toolbar_icons": "Specify one of these chars for each toolbar icon you want to show, in the order you want:\r\n('t' = tree view, 'c' = compress, 'p' = pretty-print, 'o' = path to current position)\r\nThis setting will take effect the next time you start Notepad++.\r\nIf you want there to be NO toolbar icons, enter a character that does not represent an icon; do NOT leave this field empty.", "auto_try_guess_csv_delim_newline": "If this setting is true,\r\nwhen the regex search form is opened, or when the \"Parse as CSV?\" checkbox in that form is toggled on,\r\nJsonTools will attempt to guess whether the current document is a CSV or TSV file, and how many columns and what newline it has.\r\nThe regex search form will take slightly longer to open if this is true.", "csv_newline": "Which type of newline to use for generated CSV files.", - "key_style": "The style of key to use when getting the path or key/index of a node or line", + "key_style": "The style of key to use when getting the path or key/index of a node or line.\r\nSee the documentation (https://github.com/molsonkiko/JsonToolsNppPlugin/blob/main/docs/README.md#key_style-setting) for an explanation of each type.\r\nThis setting is IGNORED when path_separator is NOT the default \"\\u0001\".", + "path_separator": "The separator to use when formatting a path. This setting is IGNORED when it is set to \"\\u0001\" (the default).\r\nThis MUST have exactly one character, which CANNOT be any of the characters in the following JSON string: \"\\\"0123456789\"\r\nThe algorithm for formatting an object key or array index is as follows:\r\n===========\r\nif the key is an array index:\r\n format it as plaintext (for example, index 10 becomes \"$10\" if \"$\" was the path_separator)\r\nif the key contains the path_separator:\r\n format it as a JSON string (for example, key \"foo\" would be formatted as \"/foo\" if \"/\" was the path_separator)\r\nelse if the key starts with (_ or a-z or A-Z) and all its other characters are (_ or 0-9 or a-z or A-Z):\r\n format it as plain text (for example, key \"_foo\" becomes \"/_foo\" if \"/\" was the path_separator, but \"_\\\"_foo\\\"\" if \"_\" was the path_separator)\r\nelse:\r\n format it as a JSON string (for example, the key \"a b\" would be formatted as \"/\\\"a b\\\"\" if the path_separator was \"/\" even though it doesn't contain the path_separator)", "skip_api_request_and_fuzz_tests": "When running tests, skip the tests that send requests to APIs and the RemesPath fuzz tests", "try_parse_start_chars": "When selecting every JSON in the file, start trying to parse only at these characters.\r\nOnly JSON valid according to the NAN_INF logger_level is tolerated.\r\nExample: if \"[{ are chosen (default), we consider only potential strings, arrays, and objects.\r\nIf \"[{tf are chosen, we consider potential strings, arrays, objects, and booleans.", "tree_view_font_size": "The font size (in points) for the tree viewer. For reference, the default value is 7.8.", diff --git a/translation/italian.json5 b/translation/italian.json5 index cc3fc45..efa73d3 100644 --- a/translation/italian.json5 +++ b/translation/italian.json5 @@ -234,8 +234,9 @@ "sort_keys": "Ordina le chiavi degli oggetti in ordine alfabetico durante la formattazione o la compressione", "toolbar_icons": "Per ogni icona della barra degli strumenti, indica una delle seguenti icone nell'ordine desiderato:\r\n('t' = visualizzazione ad albero, 'c' = compressione, 'p' = formatta, 'o' = Percorso della posizione corrente)\r\n Questa impostazione avrà effetto al riavvio di Notepad++.\r\n Per non visualizzare le icone nella barra degli strumenti, inserisci un carattere diverso dai precedenti; NON lasciare questo campo vuoto.", "auto_try_guess_csv_delim_newline": "Se questa impostazione è abilitata,\r\nquando la finestra di ricerca con espressione regolare, o quando \"Analizza come CSV?\" di questa finestra è attivata,\r\nJsonTools tenterà di indovinare se il documento corrente è un file CSV o TSV, e quante colonne e quale nuova riga contiene.\r\nIn questo caso l'apertura della finestra di ricerca espressione regolare richiederà leggermente più tempo.", - "csv_newline": "Indicare il fine riga da usare per generare file CSV.", - "key_style": "Lo stile della chiave da usare quando si ottiene il percorso o chiave/indice di un nodo o riga", + "csv_newline": "Indicare il fine riga da usare per generare file CSV.", + "key_style": "Lo stile della chiave da usare quando si ottiene il percorso o chiave/indice di un nodo o posizione.\r\nConsulta la documentazione (https://github.com/molsonkiko/JsonToolsNppPlugin/blob/main/docs/README.md#key_style-setting) per una spiegazione di ciascun tipo. Questa impostazione viene IGNORATA quando path_separator NON è l'impostazione predefinita \"\\u0001\"", + "path_separator": "Il separatore da utilizzare durante la formattazione di un percorso. Questa impostazione viene IGNORATA quando è impostata su \"\\u0001\" (impostazione predefinita).\r\nQuesto DEVE contenere esattamente un carattere, che NON PUÒ essere uno qualsiasi dei caratteri nella seguente stringa JSON: \"\\\"0123456789\"\r\nL'algoritmo per la formattazione di una chiave oggetto o di un indice di array è il seguente:\r\n===========\r\nse la chiave è un indice di array:\r\n formattarlo come testo normale (ad esempio, l'indice 10 diventa \"$10\" se \"$\" era il path_separator)\r\nse la chiave contiene il path_separator:\r\n formattarlo come una stringa JSON (ad esempio, la chiave \"foo\" verrebbe formattata come \"/foo\" se \"/\" fosse il path_separator)\r\naltrimenti se la chiave inizia con (_ o a-z o A-Z) e tutti gli altri caratteri sono (_ o 0-9 o a-z o A-Z):\r\n formattarlo come testo semplice (ad esempio, la chiave \"_foo\" diventa \"/_foo\" se \"/\" era il path_separator, ma \"_\\\"_foo\\\"\" se \"_\" era il path_separator)\r\naltro:\r\n formattarlo come una stringa JSON (ad esempio, la chiave \"a b\" verrebbe formattata come \"/\\\"a b\\\"\" se path_separator fosse \"/\" anche se non contiene path_separator)", "skip_api_request_and_fuzz_tests": "Durante l'esecuzione dei test, salta i test che inviano richieste alle API e i test RemesPath fuzz", "try_parse_start_chars": "Quando si seleziona ogni JSON nel file, iniziare a provare ad analizzare solo questi caratteri.\r\nSono ammessi solo JSON validi in base a NAN_INF logger_level.\r\nEsempio: se \"[{ sono selezionati (impostazione predefinita), vengono considerate solo stringhe, arrays, e oggetti potenziali.\r\nSe \"[{tf sono selezionate, vengono considerate stringhe, arrays, oggetti, e potenziali booleani.", "tree_view_font_size": "La dimensione del carattere (in punti) per il visualizzatore dell'albero. Per riferimento, il valore predefinito è 7,8.",