From eed8cd2c55605fec2dd02c3eeeb216b825bee6e0 Mon Sep 17 00:00:00 2001 From: ZetaMap <56844734+ZetaMap@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:49:26 +0200 Subject: [PATCH 01/12] added a way to use ANSI codes on Windows, with a very small library --- arc-core/build.gradle | 8 ++ arc-core/src/arc/util/ColorCodes.java | 102 ++++++++++++++++---------- 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/arc-core/build.gradle b/arc-core/build.gradle index 75810e102..f0874033e 100644 --- a/arc-core/build.gradle +++ b/arc-core/build.gradle @@ -5,6 +5,14 @@ sourceSets.test.resources.srcDirs = ["test/resources"] dependencies{ testImplementation libraries.junit testImplementation aproj(":natives:natives-desktop") + + if (System.getProperty("os.name").toLowerCase().contains("windows")) { + implementation "org.fusesource.jansi:jansi-native:1.1" + implementation "org.fusesource.jansi:jansi-native:1.1:windows32" + implementation "org.fusesource.jansi:jansi-native:1.1:windows64" + } else { + compileOnly "org.fusesource.jansi:jansi-native:1.1" + } } test{ diff --git a/arc-core/src/arc/util/ColorCodes.java b/arc-core/src/arc/util/ColorCodes.java index 43a09bfa5..55b198e8a 100644 --- a/arc-core/src/arc/util/ColorCodes.java +++ b/arc-core/src/arc/util/ColorCodes.java @@ -1,56 +1,73 @@ package arc.util; -import arc.struct.*; +import arc.struct.ObjectMap; + +import org.fusesource.jansi.internal.Kernel32; -/** Note that these color codes will only work on linux or mac terminals. */ public class ColorCodes{ public static String - flush = "\033[H\033[2J", - reset = "\u001B[0m", - bold = "\u001B[1m", - italic = "\u001B[3m", - underline = "\u001B[4m", - black = "\u001B[30m", - red = "\u001B[31m", - green = "\u001B[32m", - yellow = "\u001B[33m", - blue = "\u001B[34m", - purple = "\u001B[35m", - cyan = "\u001B[36m", - lightBlack = "\u001b[90m", - lightRed = "\u001B[91m", - lightGreen = "\u001B[92m", - lightYellow = "\u001B[93m", - lightBlue = "\u001B[94m", - lightMagenta = "\u001B[95m", - lightCyan = "\u001B[96m", - lightWhite = "\u001b[97m", - white = "\u001B[37m", + flush = "\033[H\033[2J", + reset = "\u001B[0m", + bold = "\u001B[1m", + italic = "\u001B[3m", + underline = "\u001B[4m", + black = "\u001B[30m", + red = "\u001B[31m", + green = "\u001B[32m", + yellow = "\u001B[33m", + blue = "\u001B[34m", + purple = "\u001B[35m", + cyan = "\u001B[36m", + lightBlack = "\u001B[90m", + lightRed = "\u001B[91m", + lightGreen = "\u001B[92m", + lightYellow = "\u001B[93m", + lightBlue = "\u001B[94m", + lightMagenta = "\u001B[95m", + lightCyan = "\u001B[96m", + lightWhite = "\u001B[97m", + white = "\u001B[37m", - backDefault = "\u001B[49m", - backRed = "\u001B[41m", - backGreen = "\u001B[42m", - backYellow = "\u001B[43m", - backBlue = "\u001B[44m"; + backDefault = "\u001B[49m", + backRed = "\u001B[41m", + backGreen = "\u001B[42m", + backYellow = "\u001B[43m", + backBlue = "\u001B[44m"; public static final String[] codes, values; + public static final boolean ansiSupported; static{ + boolean ansi = true; + + //try to enable color codes on windows, with powershell + if(OS.isWindows && !OS.hasEnv("WT_SESSION")){ + try{ + // from https://github.com/alexarchambault/windows-ansi/blob/master/jni/src/main/java/io/github/alexarchambault/windowsansi/WindowsAnsi.java + long console = Kernel32.GetStdHandle(Kernel32.STD_OUTPUT_HANDLE); + int[] mode = new int[1]; + if (Kernel32.GetConsoleMode(console, mode) == 0) throw new RuntimeException("failed to get console mode"); + mode[0] |= 0x0004; // ENABLE_VIRTUAL_TERMINAL_PROCESSING + if (Kernel32.SetConsoleMode(console, mode[0]) == 0) throw new RuntimeException("failed to set console mode"); + + }catch (Throwable e){ + System.out.println("Failed to enable ANSI escape codes: " + e.toString()); + ansi = false; + } + //disable color codes on android + }else if (OS.isAndroid){ + ansi = false; + } - //disable color codes on windows/android (ignore windows terminal which supports colors) - if((OS.isWindows && !OS.hasEnv("WT_SESSION")) || OS.isAndroid){ + ansiSupported = ansi; + + if(!ansiSupported){ flush = reset = bold = underline = black = red = green = yellow = blue = purple = cyan = lightWhite = lightBlack = lightRed = lightGreen = lightYellow = lightBlue = lightMagenta = lightCyan = white = backDefault = backRed = backYellow = backBlue = backGreen = italic = ""; } - OrderedMap map = OrderedMap.of( - "bd", backDefault, - "br", backRed, - "bg", backGreen, - "by", backYellow, - "bb", backBlue, - + ObjectMap map = ObjectMap.of( "ff", flush, "fr", reset, "fb", bold, @@ -71,11 +88,16 @@ public class ColorCodes{ "lm", lightMagenta, "lb", lightBlue, "lc", lightCyan, - "w", white + "w", white, + + "bd", backDefault, + "br", backRed, + "bg", backGreen, + "by", backYellow, + "bb", backBlue ); - codes = map.orderedKeys().toArray(String.class); + codes = map.keys().toSeq().toArray(String.class); values = map.values().toSeq().toArray(String.class); } - } From c1fae93e70ef1aa4753bfe6f9943b88fec3db69a Mon Sep 17 00:00:00 2001 From: ZetaMap <56844734+ZetaMap@users.noreply.github.com> Date: Wed, 2 Oct 2024 08:26:22 +0200 Subject: [PATCH 02/12] fixed some typo and added lot of userful methods in Strings.java --- arc-core/src/arc/util/Strings.java | 111 +++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 5 deletions(-) diff --git a/arc-core/src/arc/util/Strings.java b/arc-core/src/arc/util/Strings.java index bb8ce1f26..fd4ef190e 100644 --- a/arc-core/src/arc/util/Strings.java +++ b/arc-core/src/arc/util/Strings.java @@ -153,6 +153,11 @@ public static String stripGlyphs(CharSequence str){ return out.toString(); } + /** Remove glyphs and colors */ + public static String normalize(CharSequence str) { + return stripGlyphs(stripColors(str)); + } + private static int parseColorMarkup(CharSequence str, int start, int end){ if(start >= end) return -1; // String ended with "[". switch(str.charAt(start)){ @@ -323,8 +328,8 @@ public static String camelToKebab(String s){ return result.toString(); } - /**Converts a snake_case or kebab-case string to Upper Case. - * For example: "test_string" -> "Test String"*/ + /**Converts a snake_case or kebab-case string to Title Case. + * For example: "test_string" -> "Test String", or "TEST_STRING" -> "Test String"*/ public static String capitalize(String s){ StringBuilder result = new StringBuilder(s.length()); @@ -335,7 +340,7 @@ public static String capitalize(String s){ }else if(i == 0 || s.charAt(i - 1) == '_' || s.charAt(i - 1) == '-'){ result.append(Character.toUpperCase(c)); }else{ - result.append(c); + result.append(Character.toLowerCase(c)); } } @@ -369,7 +374,7 @@ public static String camelize(String s){ if(i == 0){ result.append(Character.toLowerCase(c)); }else if(c != ' '){ - result.append(c); + result.append(Character.toUpperCase(c)); } } @@ -491,6 +496,11 @@ public static long parseLong(String s, int radix, int start, int end, long defau } } + /** Returns Double.MIN_VALUE if parsing failed. */ + public static double parseDouble(String s){ + return parseDouble(s, Double.MIN_VALUE); + } + /** Faster double parser that doesn't throw exceptions. */ public static double parseDouble(String value, double defaultValue){ int len = value.length(); @@ -562,7 +572,7 @@ public static boolean canParsePositiveFloat(String s){ } } - /** Returns Float.NEGATIVE_INFINITY if parsing failed. */ + /** Returns Float.MIN_VALUE if parsing failed. */ public static float parseFloat(String s){ return parseFloat(s, Float.MIN_VALUE); } @@ -671,4 +681,95 @@ public static StringBuilder replace(StringBuilder builder, char find, String rep index += replaceLength; } } + + + /** @return whether the specified string mean true */ + public static boolean isTrue(String str) { + switch(str.toLowerCase()){ + case "1": case "true": case "on": + case "enable": case "activate": + return true; + default: return false; + } + } + + /** @return whether the specified string mean false */ + public static boolean isFalse(String str) { + switch (str.toLowerCase()) { + case "0": case "false": case "off": + case "disable": case "desactivate": + return true; + default: return false; + } + } + + /** @return whether {@code newVersion} string is greater than {@code currentVersion} string, e.g. "v146" > "120.1" */ + public static boolean isVersionAtLeast(String currentVersion, String newVersion) { + if (currentVersion.startsWith("v")) currentVersion = currentVersion.substring(1); + if (newVersion.startsWith("v")) newVersion = newVersion.substring(1); + + int dot = currentVersion.indexOf('.'); + int major1 = parseInt(dot == -1 ? currentVersion : currentVersion.substring(0, dot), 0); + int minor1 = dot == -1 ? 0 : parseInt(currentVersion.substring(dot + 1), 0); + dot = newVersion.indexOf('.'); + int major2 = parseInt(dot == -1 ? newVersion : newVersion.substring(0, dot), 0); + int minor2 = dot == -1 ? 0 : parseInt(newVersion.substring(dot + 1), 0); + + return major2 > major1 || (major2 == major1 && minor2 > minor1); + } + + + public static String rJust(String str, int newLenght) { + return rJust(str, newLenght, " "); + } + /** Justify string to the right. E.g. "  right" */ + public static String rJust(String str, int newLenght, String filler) { + if (filler.length() == 0) return str; // Cannot fill, so return initial string + return filler.repeat((newLenght-str.length())/filler.length())+filler.substring(0, (newLenght-str.length())%filler.length())+str; + } + public static Seq rJust(Seq list, int newLenght) { + return rJust(list, newLenght, " "); + } + public static Seq rJust(Seq list, int newLenght, String filler) { + return list.map(str -> rJust(str, newLenght, filler)); + } + + public static String lJust(String str, int newLenght) { + return lJust(str, newLenght, " "); + } + /** Justify string to the left. E.g. "left  " */ + public static String lJust(String str, int newLenght, String filler) { + if (filler.length() == 0) return str; // Cannot fill, so return initial string + return str+filler.repeat((newLenght-str.length())/filler.length())+filler.substring(0, (newLenght-str.length())%filler.length()); + } + public static Seq lJust(Seq list, int newLenght) { + return lJust(list, newLenght, " "); + } + public static Seq lJust(Seq list, int newLenght, String filler) { + return list.map(str -> lJust(str, newLenght, filler)); + } + + public static String mJust(String left, String right, int newLenght) { + return mJust(left, right, newLenght, " "); + } + /** Justify string at middle. E.g. "left   right" */ + public static String mJust(String left, String right, int newLenght, String filler) { + if (filler.length() == 0) return left+right; // Cannot fill, return concatened sides + int s = newLenght-left.length()-right.length(); + return left+filler.repeat(s/filler.length())+filler.substring(0, s%filler.length())+right; + } + public static Seq mJust(Seq left, Seq right, int newLenght) { + return mJust(left, right, newLenght, " "); + } + public static Seq mJust(Seq left, Seq right, int newLenght, String filler) { + Seq arr = new Seq<>(Integer.max(left.size, right.size)); + int i = 0; + + for (; i Date: Wed, 2 Oct 2024 08:56:22 +0200 Subject: [PATCH 03/12] fixed idents and formatting in JsonValue.java --- .../src/arc/util/serialization/JsonValue.java | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/arc-core/src/arc/util/serialization/JsonValue.java b/arc-core/src/arc/util/serialization/JsonValue.java index e4be380f9..79d205a8d 100644 --- a/arc-core/src/arc/util/serialization/JsonValue.java +++ b/arc-core/src/arc/util/serialization/JsonValue.java @@ -72,6 +72,12 @@ private static boolean isNumeric(JsonValue object){ return true; } + private static boolean needNewLine(JsonValue object, int maxChildren) { + for(JsonValue child = object.child; child != null; child = child.next) + if(child.isObject() || child.isArray() || maxChildren-- <= 0) return true; + return false; + } + private static void indent(int count, StringBuilder buffer){ for(int i = 0; i < count; i++) buffer.append('\t'); @@ -1121,7 +1127,8 @@ private void prettyPrint(JsonValue object, StringBuilder buffer, int indent, Pre if(object.child == null) buffer.append("{}"); else{ - boolean newLines = !isFlat(object); + ident++; + boolean newLines = needNewLine(object, 2); int start = buffer.length(); outer: while(true){ @@ -1130,7 +1137,7 @@ private void prettyPrint(JsonValue object, StringBuilder buffer, int indent, Pre if(newLines) indent(indent, buffer); buffer.append(outputType.quoteName(child.name)); buffer.append(": "); - prettyPrint(child, buffer, indent + 1, settings); + prettyPrint(child, buffer, indent, settings); if((!newLines || outputType != OutputType.minimal) && child.next != null) buffer.append(','); buffer.append(newLines ? '\n' : ' '); if(!newLines && buffer.length() - start > settings.singleLineColumns){ @@ -1148,7 +1155,8 @@ private void prettyPrint(JsonValue object, StringBuilder buffer, int indent, Pre if(object.child == null) buffer.append("[]"); else{ - boolean newLines = !isFlat(object); + indent++; + boolean newLines = needNewLine(object, 4); boolean wrap = settings.wrapNumericArrays || !isNumeric(object); int start = buffer.length(); outer: @@ -1156,7 +1164,7 @@ private void prettyPrint(JsonValue object, StringBuilder buffer, int indent, Pre buffer.append(newLines ? "[\n" : "[ "); for(JsonValue child = object.child; child != null; child = child.next){ if(newLines) indent(indent, buffer); - prettyPrint(child, buffer, indent + 1, settings); + prettyPrint(child, buffer, indent, settings); if((!newLines || outputType != OutputType.minimal) && child.next != null) buffer.append(','); buffer.append(newLines ? '\n' : ' '); if(wrap && !newLines && buffer.length() - start > settings.singleLineColumns){ @@ -1202,14 +1210,15 @@ private void prettyPrint(JsonValue object, Writer writer, int indent, PrettyPrin if(object.child == null) writer.append("{}"); else{ - boolean newLines = !isFlat(object) || object.size > 6; + indent++; + boolean newLines = needNewLine(object, 2); writer.append(newLines ? "{\n" : "{ "); int i = 0; for(JsonValue child = object.child; child != null; child = child.next){ if(newLines) indent(indent, writer); writer.append(outputType.quoteName(child.name)); writer.append(": "); - prettyPrint(child, writer, indent + 1, settings); + prettyPrint(child, writer, indent, settings); if((!newLines || outputType != OutputType.minimal) && child.next != null) writer.append(','); writer.append(newLines ? '\n' : ' '); } @@ -1220,12 +1229,13 @@ private void prettyPrint(JsonValue object, Writer writer, int indent, PrettyPrin if(object.child == null) writer.append("[]"); else{ - boolean newLines = !isFlat(object); + indent++; + boolean newLines = needNewLine(object, 4); writer.append(newLines ? "[\n" : "[ "); int i = 0; for(JsonValue child = object.child; child != null; child = child.next){ if(newLines) indent(indent, writer); - prettyPrint(child, writer, indent + 1, settings); + prettyPrint(child, writer, indent, settings); if((!newLines || outputType != OutputType.minimal) && child.next != null) writer.append(','); writer.append(newLines ? '\n' : ' '); } From 7eb04de05f406ea9753c2b3b5ee6444704a27e58 Mon Sep 17 00:00:00 2001 From: ZetaMap <56844734+ZetaMap@users.noreply.github.com> Date: Wed, 2 Oct 2024 09:01:14 +0200 Subject: [PATCH 04/12] oups --- arc-core/src/arc/util/serialization/JsonValue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arc-core/src/arc/util/serialization/JsonValue.java b/arc-core/src/arc/util/serialization/JsonValue.java index 79d205a8d..df5353c72 100644 --- a/arc-core/src/arc/util/serialization/JsonValue.java +++ b/arc-core/src/arc/util/serialization/JsonValue.java @@ -1127,7 +1127,7 @@ private void prettyPrint(JsonValue object, StringBuilder buffer, int indent, Pre if(object.child == null) buffer.append("{}"); else{ - ident++; + indent++; boolean newLines = needNewLine(object, 2); int start = buffer.length(); outer: From 7acf68bef31735200db6caa76a229d4d48872085 Mon Sep 17 00:00:00 2001 From: ZetaMap <56844734+ZetaMap@users.noreply.github.com> Date: Wed, 2 Oct 2024 09:08:16 +0200 Subject: [PATCH 05/12] Forget that String.repeat apear in java 11 --- arc-core/src/arc/util/Strings.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arc-core/src/arc/util/Strings.java b/arc-core/src/arc/util/Strings.java index fd4ef190e..45ff7d204 100644 --- a/arc-core/src/arc/util/Strings.java +++ b/arc-core/src/arc/util/Strings.java @@ -718,14 +718,19 @@ public static boolean isVersionAtLeast(String currentVersion, String newVersion) return major2 > major1 || (major2 == major1 && minor2 > minor1); } - + public static String repeat(String str, int count) { + String result = ""; + while (count-- > 0) result+=str; + return result; + } + public static String rJust(String str, int newLenght) { return rJust(str, newLenght, " "); } /** Justify string to the right. E.g. "  right" */ public static String rJust(String str, int newLenght, String filler) { if (filler.length() == 0) return str; // Cannot fill, so return initial string - return filler.repeat((newLenght-str.length())/filler.length())+filler.substring(0, (newLenght-str.length())%filler.length())+str; + return repeat(filler, (newLenght-str.length())/filler.length())+filler.substring(0, (newLenght-str.length())%filler.length())+str; } public static Seq rJust(Seq list, int newLenght) { return rJust(list, newLenght, " "); @@ -740,7 +745,7 @@ public static String lJust(String str, int newLenght) { /** Justify string to the left. E.g. "left  " */ public static String lJust(String str, int newLenght, String filler) { if (filler.length() == 0) return str; // Cannot fill, so return initial string - return str+filler.repeat((newLenght-str.length())/filler.length())+filler.substring(0, (newLenght-str.length())%filler.length()); + return str+repeat(filler, (newLenght-str.length())/filler.length())+filler.substring(0, (newLenght-str.length())%filler.length()); } public static Seq lJust(Seq list, int newLenght) { return lJust(list, newLenght, " "); @@ -756,7 +761,7 @@ public static String mJust(String left, String right, int newLenght) { public static String mJust(String left, String right, int newLenght, String filler) { if (filler.length() == 0) return left+right; // Cannot fill, return concatened sides int s = newLenght-left.length()-right.length(); - return left+filler.repeat(s/filler.length())+filler.substring(0, s%filler.length())+right; + return left+repeat(filler, s/filler.length())+filler.substring(0, s%filler.length())+right; } public static Seq mJust(Seq left, Seq right, int newLenght) { return mJust(left, right, newLenght, " "); From dd93abe5ee20e45d27c2c0e2d8a9a6939dd24efd Mon Sep 17 00:00:00 2001 From: ZetaMap <56844734+ZetaMap@users.noreply.github.com> Date: Wed, 16 Oct 2024 18:54:42 +0200 Subject: [PATCH 06/12] remaked isVersionAtLeast() for a better one --- arc-core/src/arc/util/Strings.java | 38 +++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/arc-core/src/arc/util/Strings.java b/arc-core/src/arc/util/Strings.java index 45ff7d204..09bb22894 100644 --- a/arc-core/src/arc/util/Strings.java +++ b/arc-core/src/arc/util/Strings.java @@ -703,19 +703,41 @@ public static boolean isFalse(String str) { } } - /** @return whether {@code newVersion} string is greater than {@code currentVersion} string, e.g. "v146" > "120.1" */ + /** + * @return whether {@code newVersion} is greater than {@code currentVersion} , e.g. "v146" > "124.1" + * @apiNote can handle multiple dots in the version, and it's very fast because it only does one iteration. + */ public static boolean isVersionAtLeast(String currentVersion, String newVersion) { if (currentVersion.startsWith("v")) currentVersion = currentVersion.substring(1); if (newVersion.startsWith("v")) newVersion = newVersion.substring(1); - int dot = currentVersion.indexOf('.'); - int major1 = parseInt(dot == -1 ? currentVersion : currentVersion.substring(0, dot), 0); - int minor1 = dot == -1 ? 0 : parseInt(currentVersion.substring(dot + 1), 0); - dot = newVersion.indexOf('.'); - int major2 = parseInt(dot == -1 ? newVersion : newVersion.substring(0, dot), 0); - int minor2 = dot == -1 ? 0 : parseInt(newVersion.substring(dot + 1), 0); + int last1 = 0, last2 = 0, dot1 = 0, dot2 = 0, p1 = 0, p2 = 0; + int len1 = currentVersion.length(), len2 = newVersion.length(); - return major2 > major1 || (major2 == major1 && minor2 > minor1); + while ((dot1 != -1 && dot2 != -1) && (last1 < len1 && last2 < len2)) { + dot1 = currentVersion.indexOf('.', last1); + dot2 = newVersion.indexOf('.', last2); + if (dot1 == -1) dot1 = len1; + if (dot2 == -1) dot2 = len2; + + p1 = parseInt(currentVersion, 10, 0, last1, dot1); + p2 = parseInt(newVersion, 10, 0, last2, dot2); + last1 = dot1+1; + last2 = dot2+1; + + if (p1 != p2) return p2 > p1; + } + + // Continue iteration on newVersion to see if it's just leading zeros. + while (dot2 != -1 && last2 < len2) { + dot2 = newVersion.indexOf('.', last2); + if (dot2 == -1) dot2 = len2; + p2 = parseInt(newVersion, 10, 0, last2, dot2); + last2 = dot2+1; + if (p2 > 0) return true; + } + + return false; } public static String repeat(String str, int count) { From 27111972f7e7108ed3aed1190a766fc866aeea88 Mon Sep 17 00:00:00 2001 From: ZetaMap <56844734+ZetaMap@users.noreply.github.com> Date: Wed, 16 Oct 2024 19:00:09 +0200 Subject: [PATCH 07/12] better than better XD --- arc-core/src/arc/util/Strings.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arc-core/src/arc/util/Strings.java b/arc-core/src/arc/util/Strings.java index 09bb22894..2b3331d43 100644 --- a/arc-core/src/arc/util/Strings.java +++ b/arc-core/src/arc/util/Strings.java @@ -708,12 +708,13 @@ public static boolean isFalse(String str) { * @apiNote can handle multiple dots in the version, and it's very fast because it only does one iteration. */ public static boolean isVersionAtLeast(String currentVersion, String newVersion) { - if (currentVersion.startsWith("v")) currentVersion = currentVersion.substring(1); - if (newVersion.startsWith("v")) newVersion = newVersion.substring(1); - - int last1 = 0, last2 = 0, dot1 = 0, dot2 = 0, p1 = 0, p2 = 0; - int len1 = currentVersion.length(), len2 = newVersion.length(); - + int last1 = currentVersion.startsWith("v") ? 1 : 0, + last2 = newVersion.startsWith("v") ? 1 : 0, + len1 = currentVersion.length(), + len2 = newVersion.length(), + dot1 = 0, dot2 = 0, + p1 = 0, p2 = 0; + while ((dot1 != -1 && dot2 != -1) && (last1 < len1 && last2 < len2)) { dot1 = currentVersion.indexOf('.', last1); dot2 = newVersion.indexOf('.', last2); From 2ed481deae106cf3773a3c0fe7dfeb3bb902034b Mon Sep 17 00:00:00 2001 From: ZetaMap <56844734+ZetaMap@users.noreply.github.com> Date: Fri, 25 Oct 2024 22:42:50 +0200 Subject: [PATCH 08/12] Some typo fixes, added new functions. Next i will add a "tableify" method --- arc-core/src/arc/util/Strings.java | 149 +++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 39 deletions(-) diff --git a/arc-core/src/arc/util/Strings.java b/arc-core/src/arc/util/Strings.java index 2b3331d43..9e7beb627 100644 --- a/arc-core/src/arc/util/Strings.java +++ b/arc-core/src/arc/util/Strings.java @@ -702,7 +702,37 @@ public static boolean isFalse(String str) { default: return false; } } - + + public static int best(Iterable list, Intf intifier) { + int best = 0; + + for (T i : list) { + int s = intifier.get(i); + if (s > best) best = s; + } + + return best; + } + + public static int best(T[] list, Intf intifier) { + int best = 0; + + for (T i : list) { + int s = intifier.get(i); + if (s > best) best = s; + } + + return best; + } + + public static int bestLength(Iterable list) { + return best(list, str -> str.length()); + } + + public static int bestLength(String... list) { + return best(list, str -> str.length()); + } + /** * @return whether {@code newVersion} is greater than {@code currentVersion} , e.g. "v146" > "124.1" * @apiNote can handle multiple dots in the version, and it's very fast because it only does one iteration. @@ -741,62 +771,103 @@ public static boolean isVersionAtLeast(String currentVersion, String newVersion) return false; } + /** Taken from the {@link String#repeat(int)} method of JDK 11 */ public static String repeat(String str, int count) { - String result = ""; - while (count-- > 0) result+=str; - return result; + if (count < 0) { + throw new IllegalArgumentException("count is negative: " + count); + } + if (count == 1) { + return str; + } + final byte[] value = str.getBytes(); + final int len = value.length; + if (len == 0 || count == 0) { + return ""; + } + if (Integer.MAX_VALUE / count < len) { + throw new OutOfMemoryError("Required length exceeds implementation limit"); + } + if (len == 1) { + final byte[] single = new byte[count]; + java.util.Arrays.fill(single, value[0]); + return new String(single); + } + final int limit = len * count; + final byte[] multiple = new byte[limit]; + System.arraycopy(value, 0, multiple, 0, len); + int copied = len; + for (; copied < limit - copied; copied <<= 1) { + System.arraycopy(multiple, 0, multiple, copied, copied); + } + System.arraycopy(multiple, 0, multiple, copied, limit - copied); + return new String(multiple); } - public static String rJust(String str, int newLenght) { - return rJust(str, newLenght, " "); - } + public static String rJust(String str, int length) { return rJust(str, length, " "); } /** Justify string to the right. E.g. "  right" */ - public static String rJust(String str, int newLenght, String filler) { - if (filler.length() == 0) return str; // Cannot fill, so return initial string - return repeat(filler, (newLenght-str.length())/filler.length())+filler.substring(0, (newLenght-str.length())%filler.length())+str; - } - public static Seq rJust(Seq list, int newLenght) { - return rJust(list, newLenght, " "); + public static String rJust(String str, int length, String filler) { + int sSize = str.length(), fSize = filler.length(); + + if (fSize == 0 || sSize >= length) return str; + if (fSize == 1) return filler.repeat(length-sSize)+str; + int add = length-sSize; + return filler.repeat(add/fSize)+filler.substring(0, add%fSize)+str; } - public static Seq rJust(Seq list, int newLenght, String filler) { - return list.map(str -> rJust(str, newLenght, filler)); + public static Seq rJust(Seq list, int length) { return rJust(list, length, " "); } + public static Seq rJust(Seq list, int length, String filler) { + return list.map(str -> rJust(str, length, filler)); } - public static String lJust(String str, int newLenght) { - return lJust(str, newLenght, " "); - } + public static String lJust(String str, int length) { return lJust(str, length, " "); } /** Justify string to the left. E.g. "left  " */ - public static String lJust(String str, int newLenght, String filler) { - if (filler.length() == 0) return str; // Cannot fill, so return initial string - return str+repeat(filler, (newLenght-str.length())/filler.length())+filler.substring(0, (newLenght-str.length())%filler.length()); - } - public static Seq lJust(Seq list, int newLenght) { - return lJust(list, newLenght, " "); + public static String lJust(String str, int length, String filler) { + int sSize = str.length(), fSize = filler.length(); + + if (fSize == 0 || sSize >= length) return str; + if (fSize == 1) return str+filler.repeat(length-sSize); + int add = length-sSize; + return str+filler.repeat(add/fSize)+filler.substring(0, add%fSize); } - public static Seq lJust(Seq list, int newLenght, String filler) { - return list.map(str -> lJust(str, newLenght, filler)); + public static Seq lJust(Seq list, int length) { return lJust(list, length, " "); } + public static Seq lJust(Seq list, int length, String filler) { + return list.map(str -> lJust(str, length, filler)); } - public static String mJust(String left, String right, int newLenght) { - return mJust(left, right, newLenght, " "); + public static String cJust(String str, int length) { return cJust(str, length, " "); } + /** Justify string to the center. E.g. "  center  ". */ + public static String cJust(String str, int length, String filler) { + int sSize = str.length(), fSize = filler.length(); + + if (fSize == 0 || sSize >= length) return str; + int add = length-sSize, left = add/2, right = add-add/2; + if (fSize == 1) return filler.repeat(left)+str+filler.repeat(right); + return filler.repeat(left/fSize)+filler.substring(0, left%fSize)+str+ + filler.repeat(right/fSize)+filler.substring(0, right%fSize); } - /** Justify string at middle. E.g. "left   right" */ - public static String mJust(String left, String right, int newLenght, String filler) { - if (filler.length() == 0) return left+right; // Cannot fill, return concatened sides - int s = newLenght-left.length()-right.length(); - return left+repeat(filler, s/filler.length())+filler.substring(0, s%filler.length())+right; + public static Seq cJust(Seq list, int length) { return cJust(list, length, " "); } + public static Seq cJust(Seq list, int length, String filler) { + return list.map(str -> cJust(str, length, filler)); } - public static Seq mJust(Seq left, Seq right, int newLenght) { - return mJust(left, right, newLenght, " "); + + public static String sJust(String left, String right, int length) { return sJust(left, right, length, " "); } + /** Justify string to the sides. E.g. "left   right" */ + public static String sJust(String left, String right, int length, String filler) { + int fSize = filler.length(), lSize = left.length(), rSize = right.length(); + + if (fSize == 0 || lSize+rSize >= length) return left+right; + int add = length-lSize-rSize; + if (fSize == 1) return left+filler.repeat(add)+right; + return left+filler.repeat(add/fSize)+filler.substring(0, add%fSize)+right; } - public static Seq mJust(Seq left, Seq right, int newLenght, String filler) { + public static Seq sJust(Seq left, Seq right, int length) { return sJust(left, right, length, " "); } + public static Seq sJust(Seq left, Seq right, int length, String filler) { Seq arr = new Seq<>(Integer.max(left.size, right.size)); int i = 0; - for (; i Date: Sat, 26 Oct 2024 13:12:18 +0200 Subject: [PATCH 09/12] forgot that --- arc-core/src/arc/util/Strings.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arc-core/src/arc/util/Strings.java b/arc-core/src/arc/util/Strings.java index 9e7beb627..c258143fa 100644 --- a/arc-core/src/arc/util/Strings.java +++ b/arc-core/src/arc/util/Strings.java @@ -809,9 +809,9 @@ public static String rJust(String str, int length, String filler) { int sSize = str.length(), fSize = filler.length(); if (fSize == 0 || sSize >= length) return str; - if (fSize == 1) return filler.repeat(length-sSize)+str; + if (fSize == 1) return repeat(filler, length-sSize)+str; int add = length-sSize; - return filler.repeat(add/fSize)+filler.substring(0, add%fSize)+str; + return repeat(filler, add/fSize)+filler.substring(0, add%fSize)+str; } public static Seq rJust(Seq list, int length) { return rJust(list, length, " "); } public static Seq rJust(Seq list, int length, String filler) { @@ -824,9 +824,9 @@ public static String lJust(String str, int length, String filler) { int sSize = str.length(), fSize = filler.length(); if (fSize == 0 || sSize >= length) return str; - if (fSize == 1) return str+filler.repeat(length-sSize); + if (fSize == 1) return str+repeat(filler, length-sSize); int add = length-sSize; - return str+filler.repeat(add/fSize)+filler.substring(0, add%fSize); + return str+repeat(filler, add/fSize)+filler.substring(0, add%fSize); } public static Seq lJust(Seq list, int length) { return lJust(list, length, " "); } public static Seq lJust(Seq list, int length, String filler) { @@ -840,9 +840,9 @@ public static String cJust(String str, int length, String filler) { if (fSize == 0 || sSize >= length) return str; int add = length-sSize, left = add/2, right = add-add/2; - if (fSize == 1) return filler.repeat(left)+str+filler.repeat(right); - return filler.repeat(left/fSize)+filler.substring(0, left%fSize)+str+ - filler.repeat(right/fSize)+filler.substring(0, right%fSize); + if (fSize == 1) return repeat(filler, left)+str+repeat(filler, right); + return repeat(filler, left/fSize)+filler.substring(0, left%fSize)+str+ + repeat(filler, right/fSize)+filler.substring(0, right%fSize); } public static Seq cJust(Seq list, int length) { return cJust(list, length, " "); } public static Seq cJust(Seq list, int length, String filler) { @@ -856,8 +856,8 @@ public static String sJust(String left, String right, int length, String filler) if (fSize == 0 || lSize+rSize >= length) return left+right; int add = length-lSize-rSize; - if (fSize == 1) return left+filler.repeat(add)+right; - return left+filler.repeat(add/fSize)+filler.substring(0, add%fSize)+right; + if (fSize == 1) return left+repeat(filler, add)+right; + return left+repeat(filler, add/fSize)+filler.substring(0, add%fSize)+right; } public static Seq sJust(Seq left, Seq right, int length) { return sJust(left, right, length, " "); } public static Seq sJust(Seq left, Seq right, int length, String filler) { From 8541e8ad905cc1380d7c1ce49816ae47a5a21dd5 Mon Sep 17 00:00:00 2001 From: ZetaMap <56844734+ZetaMap@users.noreply.github.com> Date: Sun, 27 Oct 2024 09:43:15 +0100 Subject: [PATCH 10/12] mmm --- arc-core/src/arc/util/Strings.java | 1 + 1 file changed, 1 insertion(+) diff --git a/arc-core/src/arc/util/Strings.java b/arc-core/src/arc/util/Strings.java index c258143fa..8bd6a0eba 100644 --- a/arc-core/src/arc/util/Strings.java +++ b/arc-core/src/arc/util/Strings.java @@ -2,6 +2,7 @@ import arc.graphics.*; import arc.struct.*; +import arc.func.*; import java.io.*; import java.net.*; From 5762d66e228ea19910ace42e1999c31009a663ea Mon Sep 17 00:00:00 2001 From: ZetaMap <56844734+ZetaMap@users.noreply.github.com> Date: Sat, 2 Nov 2024 15:34:24 +0100 Subject: [PATCH 11/12] added the "tableify" method --- arc-core/src/arc/util/Strings.java | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arc-core/src/arc/util/Strings.java b/arc-core/src/arc/util/Strings.java index 8bd6a0eba..ba903cd72 100644 --- a/arc-core/src/arc/util/Strings.java +++ b/arc-core/src/arc/util/Strings.java @@ -872,4 +872,39 @@ public static Seq sJust(Seq left, Seq right, int length, return arr; } + + public static Seq tableify(Seq lines, int maxLength) { + return tableify(lines, maxLength, Strings::lJust); + } + /** + * Create a table with given {@code lines} + * and automatic columns number calculated with the table's {@code width}. + */ + public static Seq tableify(Seq lines, int maxLength, + Func2 justifier) { + int spacing = 2, // Additional spacing between columns + columns = Math.max(1, maxLength / (bestLength(lines) + 2)); // Estimate the columns + Seq result = new Seq<>(lines.size / columns + 1); + int[] bests = new int[columns]; + StringBuilder builder = new StringBuilder(); + + // Calculate the best length for each columns + for (int i=0, c=0, s=0; i bests[c]) bests[c] = s; + } + + // Now justify lines + for (int i=0, c; i Date: Sat, 2 Nov 2024 15:36:33 +0100 Subject: [PATCH 12/12] better parameter naming --- arc-core/src/arc/util/Strings.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arc-core/src/arc/util/Strings.java b/arc-core/src/arc/util/Strings.java index ba903cd72..104d47e40 100644 --- a/arc-core/src/arc/util/Strings.java +++ b/arc-core/src/arc/util/Strings.java @@ -873,17 +873,17 @@ public static Seq sJust(Seq left, Seq right, int length, return arr; } - public static Seq tableify(Seq lines, int maxLength) { - return tableify(lines, maxLength, Strings::lJust); + public static Seq tableify(Seq lines, int width) { + return tableify(lines, width, Strings::lJust); } /** * Create a table with given {@code lines} * and automatic columns number calculated with the table's {@code width}. */ - public static Seq tableify(Seq lines, int maxLength, + public static Seq tableify(Seq lines, int width, Func2 justifier) { int spacing = 2, // Additional spacing between columns - columns = Math.max(1, maxLength / (bestLength(lines) + 2)); // Estimate the columns + columns = Math.max(1, width / (bestLength(lines) + 2)); // Estimate the columns Seq result = new Seq<>(lines.size / columns + 1); int[] bests = new int[columns]; StringBuilder builder = new StringBuilder(); @@ -906,5 +906,4 @@ public static Seq tableify(Seq lines, int maxLength, return result; } - }