diff --git a/CHANGELOG.md b/CHANGELOG.md index 99cddbe..4b7121d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed 1. Hopefully eliminated crash bug that sometimes seems to happen because a file that had a tree viewer associated with it was renamed. This bug is really unpredictable, so it may not be gone. -2. Changed [RemesPath `s_sub` function](/docs/RemesPath.md#vectorized-functions) so that it either does regex-replace or simple string-replace, depending on the type of the second parameter. +2. Fixed bug in [Main](/JsonToolsNppPlugin/Main.cs#L360) (based on failure to read [SCI_GETTEXT documentation](https://www.scintilla.org/ScintillaDoc.html#SCI_GETTEXT)) that caused this plugin to be incompatible with versions of Notepad++ older than 8.4.1. + +### Changed +1. Changed [RemesPath `s_sub` function](/docs/RemesPath.md#vectorized-functions) so that it either does regex-replace or simple string-replace, depending on the type of the second parameter. + +#### Added +1. [DSON emitter and UDL](/docs/README.md#dson) takes this plugin to the moon! ## [4.10.0] - 2023-02-15 diff --git a/DSON UDL.xml b/DSON UDL.xml new file mode 100644 index 0000000..84ab86c --- /dev/null +++ b/DSON UDL.xml @@ -0,0 +1,64 @@ + + + + + + + + 00 01 02 03 04 + + - + + + + + + VERY very + , ? . ! + + + + + + + + + + + so and also many + such is wow + yes no + empty + + + + + 00" 01\ 02" 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JsonToolsNppPlugin/JSONTools/Dson.cs b/JsonToolsNppPlugin/JSONTools/Dson.cs new file mode 100644 index 0000000..e063caa --- /dev/null +++ b/JsonToolsNppPlugin/JSONTools/Dson.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace JSON_Tools.JSON_Tools +{ + class DsonDumpException : Exception + { + public new string Message; + + public DsonDumpException(string message) + { + Message = message; + } + } + + /// + /// wow such data very readable

+ /// such docs at https://dogeon.xyz/ plz read + ///
+ class Dson + { + public static string KeyValuePairDelims = ",.!?"; + + public static string[] ArrayPairDelims = new string[] { "and", "also" }; + + private static string FormatInteger(long val) + { + if (val == long.MinValue) + // converting to octal turns signed numbers into unsigned numbers + // this can be reversed for every negative number except long.MinValue + return "1000000000000000000000"; + if (val < 0) + return "-" + Convert.ToString(-val, 8); + return Convert.ToString(val, 8); + } + + /// + /// plz stringify json as DSON

+ /// wow so amaze + ///
+ public static string Dump(JNode json) + { + StringBuilder sb; + switch (json.type) + { + case Dtype.ARR: + sb = new StringBuilder(); + sb.Append("so "); + JArray arr = (JArray)json; + bool useAndDelim = true; + for (int ii = 0; ii < arr.Length; ii++) + { + sb.Append(Dump(arr[ii])); + sb.Append(useAndDelim ? " and " : " also "); + useAndDelim = !useAndDelim; + } + if (arr.Length > 0) + { + // trim off the last delimiter if the array had items + int lengthToRemove = useAndDelim ? 5 : 4; + sb.Remove(sb.Length - lengthToRemove - 1, lengthToRemove); + } + sb.Append("many"); + return sb.ToString(); + case Dtype.OBJ: + // {"a": 13.51e25, "b": true} becomes + // such "a" is 15.63very31, "b" is yes wow + sb = new StringBuilder(); + sb.Append("such "); + int delimIdx = 0; + JObject obj = (JObject)json; + foreach (string key in obj.children.Keys) + { + JNode value = obj[key]; + sb.Append($"\"{key}\" is "); + sb.Append(Dump(value)); + sb.Append(KeyValuePairDelims[delimIdx % 4] + " "); + delimIdx++; + } + if (obj.Length > 0) + sb.Remove(sb.Length - 2, 1); // remove the last delimter if there were items + sb.Append("wow"); + return sb.ToString(); + case Dtype.BOOL: + return (bool)json.value ? "yes" : "no"; + case Dtype.NULL: + return "empty"; + case Dtype.INT: + return FormatInteger((long)json.value); + case Dtype.FLOAT: + // floating point numbers are formatted + // such that fractional part, exponent, and integer part are all octal + string valstr = ((double)json.value).ToString(); + if (valstr.EndsWith("y") || valstr.EndsWith("N")) + // Infinity and NaN are not in the DSON specification + throw new DsonDumpException($"{valstr} is fake number, can't understand. So silly, wow"); + StringBuilder partSb = new StringBuilder(); + sb = new StringBuilder(); + long part; + foreach (char c in valstr) + { + if ('0' <= c && c <= '9' || c == '+' || c == '-') + { + partSb.Append(c); + } + else + { + part = Convert.ToInt64(partSb.ToString()); + partSb = new StringBuilder(); + sb.Append(FormatInteger(part)); + if (c == '.') + sb.Append("."); + else if (c == 'e') + sb.Append("very"); + else if (c == 'E') + sb.Append("VERY"); + } + } + part = Convert.ToInt64(partSb.ToString()); + sb.Append(FormatInteger(part)); + return sb.ToString(); + case Dtype.STR: + return json.ToString(); + default: throw new NotSupportedException(); + } + } + } +} diff --git a/JsonToolsNppPlugin/JSONTools/RandomJsonFromSchema.cs b/JsonToolsNppPlugin/JSONTools/RandomJsonFromSchema.cs index 6f14d75..835b242 100644 --- a/JsonToolsNppPlugin/JSONTools/RandomJsonFromSchema.cs +++ b/JsonToolsNppPlugin/JSONTools/RandomJsonFromSchema.cs @@ -76,7 +76,7 @@ private static JNode RandomString(JNode schema, int minArrayLength, int maxArray { for (int ii = 0; ii < length; ii++) { - char randChar = EXTENDED_ASCII[random.Next(256)]; + char randChar = EXTENDED_ASCII[random.Next(1, 256)]; // not allowing \x00 because that will terminate string early in C sb.Append(randChar); } } @@ -227,6 +227,10 @@ private static JNode RandomAnything(JNode schema, int minArrayLength, int maxArr } } + /// + /// choose a random schema from an anyOf list of schemas, and make random JSON based on that schema + /// + /// private static JNode RandomAnyOf(JNode anyOf, int minArrayLength, int maxArrayLength, bool extended_ascii_strings) { JArray anyOfArr = (JArray)anyOf; diff --git a/JsonToolsNppPlugin/JsonToolsNppPlugin.csproj b/JsonToolsNppPlugin/JsonToolsNppPlugin.csproj index d900c03..1eb1ff0 100644 --- a/JsonToolsNppPlugin/JsonToolsNppPlugin.csproj +++ b/JsonToolsNppPlugin/JsonToolsNppPlugin.csproj @@ -97,6 +97,7 @@ TreeViewer.cs + @@ -193,6 +194,7 @@ + diff --git a/JsonToolsNppPlugin/Main.cs b/JsonToolsNppPlugin/Main.cs index 629913a..2bd508e 100644 --- a/JsonToolsNppPlugin/Main.cs +++ b/JsonToolsNppPlugin/Main.cs @@ -14,6 +14,7 @@ using JSON_Tools.Utils; using JSON_Tools.Forms; using JSON_Tools.Tests; +using System.Runtime.InteropServices.WindowsRuntime; namespace Kbg.NppPluginNET { @@ -49,7 +50,6 @@ class Main static internal int jsonTreeId = -1; static internal int grepperFormId = -1; static internal int AboutFormId = -1; - //static internal int nodeSelectedLabelId = -1; #endregion #region " Startup/CleanUp " @@ -87,7 +87,8 @@ static internal void CommandMenuInit() PluginBase.SetCommand(14, "---", null); PluginBase.SetCommand(15, "JSON to &YAML", DumpYaml); PluginBase.SetCommand(16, "Run &tests", async () => await TestRunner.RunAll()); - PluginBase.SetCommand(17, "A&bout", ShowAboutForm); AboutFormId = 16; + PluginBase.SetCommand(17, "A&bout", ShowAboutForm); AboutFormId = 17; + PluginBase.SetCommand(18, "&Wow such doge", Dogeify); //// read schemas_to_fname_patterns.json in config directory (if it exists) //string config_dir = Npp.notepad.GetConfigDirectory(); @@ -356,7 +357,7 @@ public static JNode TryParseJson(bool is_json_lines = false) { int len = Npp.editor.GetLength(); string fname = Npp.notepad.GetCurrentFilePath(); - string text = Npp.editor.GetText(len); + string text = Npp.editor.GetText(len + 1); JNode json = new JNode(); try { @@ -781,6 +782,24 @@ static void ShowAboutForm() aboutForm.Focus(); } + static void Dogeify() + { + JNode json = TryParseJson(); + if (json == null) return; + try + { + string dson = Dson.Dump(json); + Npp.notepad.FileNew(); + Npp.editor.SetText(dson); + } + catch (Exception ex) + { + MessageBox.Show($"Could not convert JSON to DSON. Got exception:\r\n{ex}", + "such error very sad", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + //static void MapSchemasToFnamePatterns() //{ // string config_dir = Npp.notepad.GetConfigDirectory(); diff --git a/JsonToolsNppPlugin/PluginInfrastructure/NotepadPPGateway.cs b/JsonToolsNppPlugin/PluginInfrastructure/NotepadPPGateway.cs index 1f086eb..6f391a1 100644 --- a/JsonToolsNppPlugin/PluginInfrastructure/NotepadPPGateway.cs +++ b/JsonToolsNppPlugin/PluginInfrastructure/NotepadPPGateway.cs @@ -25,6 +25,7 @@ public interface INotepadPPGateway Color GetDefaultForegroundColor(); Color GetDefaultBackgroundColor(); string GetConfigDirectory(); + int[] GetNppVersion(); } /// @@ -174,6 +175,19 @@ public string GetConfigDirectory() Win32.SendMessage(PluginBase.nppData._nppHandle, (uint)NppMsg.NPPM_GETPLUGINSCONFIGDIR, Win32.MAX_PATH, sbIniFilePath); return sbIniFilePath.ToString(); } + + /// + /// 2-int array. First entry: major version. Second entry: minor version + /// + /// + public int[] GetNppVersion() + { + // the low word (i.e., version & 0xffff + int version = Win32.SendMessage(PluginBase.nppData._nppHandle, (uint)NppMsg.NPPM_GETNPPVERSION, 0, 0).ToInt32(); + int minor = version & 0xffff; + int major = version >> 16; + return new int[] { major, minor }; + } } /// diff --git a/JsonToolsNppPlugin/Properties/AssemblyInfo.cs b/JsonToolsNppPlugin/Properties/AssemblyInfo.cs index f2eef53..4acecb9 100644 --- a/JsonToolsNppPlugin/Properties/AssemblyInfo.cs +++ b/JsonToolsNppPlugin/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion("4.10.0.2")] -[assembly: AssemblyFileVersion("4.10.0.2")] +[assembly: AssemblyVersion("4.10.0.3")] +[assembly: AssemblyFileVersion("4.10.0.3")] diff --git a/JsonToolsNppPlugin/Tests/DsonTests.cs b/JsonToolsNppPlugin/Tests/DsonTests.cs new file mode 100644 index 0000000..769d2c8 --- /dev/null +++ b/JsonToolsNppPlugin/Tests/DsonTests.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; +using JSON_Tools.JSON_Tools; +using JSON_Tools.Utils; + +namespace JSON_Tools.Tests +{ + public class DsonTester + { + public static void TestDump() + { + (string inp, string correctOut)[] testcases = new (string inp, string correctOut)[] + { + ("[]", "so many"), + ("{}", "such wow"), + ("[1]", "so 1 many"), + ("{\"a\": 13}", "such \"a\" is 15 wow"), + ("null", "empty"), + ("[1.5, [2e31], -3.5E40]", "so 1.5 and so 2VERY37 many also -3.5VERY50 many"), + ("{\"aჿ\":[true,false,{\"c\": 3},\"оa\",[1, -2]], \"b\\\"\": \"z\", \"c\": {\"d\": 1.13}, \"d\": 50, \"e\": 0.76, \"f\": null}", + "such \"aჿ\" is so yes and no also such \"c\" is 3 wow and \"оa\" also so 1 and -2 many many, \"b\\\"\" is \"z\". " + + "\"c\" is such \"d\" is 1.15 wow! \"d\" is 62? \"e\" is 0.114, \"f\" is empty wow"), + ("[-9223372036854775808, 9223372036854775807]", "so 1000000000000000000000 and 777777777777777777777 many"), + }; + int tests_failed = 0; + int ii = 0; + JsonParser parser = new JsonParser(); + foreach ((string input, string correctOut) in testcases) + { + JNode json = JsonParserTester.TryParse(input, parser); + if (json == null) continue; + ii++; + string dson; + try + { + dson = Dson.Dump(json); + } + catch (Exception ex) + { + tests_failed++; + string msg = $"Tried to parse json\r\n{json}\r\nas dson\r\n{correctOut}\r\nbut got error:\r\n{ex}\r\n"; + Npp.editor.AppendText(Encoding.UTF8.GetByteCount(msg), msg); + continue; + } + if (dson != correctOut) + { + tests_failed++; + string msg = $"Expected json\r\n{json}\r\nto be emitted\r\nas dson\r\n{correctOut}\r\nbut instead got \r\n{dson}\r\n"; + Npp.editor.AppendText(Encoding.UTF8.GetByteCount(msg), msg); + } + } + Npp.AddLine($"Failed {tests_failed} tests."); + Npp.AddLine($"Passed {ii - tests_failed} tests."); + } + } +} diff --git a/JsonToolsNppPlugin/Tests/TestRunner.cs b/JsonToolsNppPlugin/Tests/TestRunner.cs index e2400db..08d9de7 100644 --- a/JsonToolsNppPlugin/Tests/TestRunner.cs +++ b/JsonToolsNppPlugin/Tests/TestRunner.cs @@ -131,6 +131,12 @@ Testing ArgFunctions "); RandomJsonTests.TestRandomJson(); + Npp.AddLine(@"========================= +Testing conversion of JSON to DSON (see https://dogeon.xyz/) +========================= +"); + DsonTester.TestDump(); + Npp.AddLine(@"========================= Performance tests for JsonParser ========================= diff --git a/JsonToolsNppPlugin/Utils/FormStyle.cs b/JsonToolsNppPlugin/Utils/FormStyle.cs index f2de107..2d1754f 100644 --- a/JsonToolsNppPlugin/Utils/FormStyle.cs +++ b/JsonToolsNppPlugin/Utils/FormStyle.cs @@ -25,6 +25,9 @@ public static class FormStyle public static void ApplyStyle(Form form, bool use_npp_style) { if (form.IsDisposed) return; + int[] version = Npp.notepad.GetNppVersion(); + if (version[0] < 8) + use_npp_style = false; // trying to follow editor style looks weird for Notepad++ 7.3.3 //foreach (PropertyInfo info in form.GetType().GetProperties()) //{ // if (info.PropertyType.IsSubclassOf(form_type)) diff --git a/docs/DSON example.PNG b/docs/DSON example.PNG new file mode 100644 index 0000000..c561435 Binary files /dev/null and b/docs/DSON example.PNG differ diff --git a/docs/README.md b/docs/README.md index 82582d4..5f88c12 100644 --- a/docs/README.md +++ b/docs/README.md @@ -446,4 +446,12 @@ This JSON schema generator only produces schemas with the following keywords: ### Keywords for arrays * [items](https://json-schema.org/draft/2020-12/json-schema-core.html#name-items) -![JSON schema generator](/docs/json%20viewer%20schema%20generator.PNG) \ No newline at end of file +![JSON schema generator](/docs/json%20viewer%20schema%20generator.PNG) + +## DSON ## + +JSON is not sufficiently [Doge-friendly](https://dogeon.xyz/index.html). This plugin aims to help correct that. + +Currently the plugin only has a DSON emitter. Later I will add a DSON parser. + +![DSON example](/docs/DSON%20example.PNG) \ No newline at end of file diff --git a/testfiles/small/subsmall/to the moon.dson b/testfiles/small/subsmall/to the moon.dson new file mode 100644 index 0000000..f0643d9 --- /dev/null +++ b/testfiles/small/subsmall/to the moon.dson @@ -0,0 +1 @@ +so such "aჿ" is so yes and no also such "c" is 3 wow and "оa" also so 1 and -2 many many, "b\"" is "z". "c" is such "d" is 1.15 wow! "d" is 62? "e" is 0.114, "f" is empty wow and so 1.5 and so 2very37 many also -3.5VERY50 many many