From f1a8f7ffd2963bd4044c77732696ca6dac19b7e9 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali Date: Tue, 15 Mar 2022 15:56:31 +0300 Subject: [PATCH 01/23] =?UTF-8?q?=F0=9F=9A=80=20Add=20number=20format=20ex?= =?UTF-8?q?pression?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skript/expressions/ExprFormatNumber.java | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java new file mode 100644 index 00000000000..efb65b9de10 --- /dev/null +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -0,0 +1,109 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package ch.njol.skript.expressions; + +import ch.njol.skript.Metrics; +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.PropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.VariableString; +import ch.njol.skript.util.Getter; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.eclipse.jdt.annotation.Nullable; + +import java.text.DecimalFormat; + +@Name("Formatted Number") +@Description("Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') will be used. For reference, see this " + + "article.") +@Examples({ + "command /formatnumber :", + "\taliases: fn", + "\ttrigger:", + "\t\tsend \"Formatted: %formatted arg-1%\" to sender" +}) +@Since("INSERT VERSION") +public class ExprFormatNumber extends PropertyExpression { + + private static final String defaultFormat = "###,###"; + + static { + Skript.registerExpression(ExprFormatNumber.class, String.class, ExpressionType.PROPERTY, + "%numbers% formatted [human-readable] [(with|as) %-string%]", + "[human-readable] formatted %numbers% [(with|as) %-string%]"); + } + + @SuppressWarnings("null") + private DecimalFormat format; + + @Override + @SuppressWarnings("null") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + setExpr((Expression) exprs[0]); + if (exprs[1] != null) { + if (!(exprs[1] instanceof Literal)) { + VariableString str = (VariableString) exprs[1]; + if (!str.isSimple()) { + Skript.error("Number format must not contain variables!"); + return false; + } + } + String customFormat = (String) exprs[1].getSingle(null); + try { + format = new DecimalFormat(customFormat); + } catch (Exception e) { + Skript.error("Incorrect number format used: " + e.getMessage()); + return false; + } + } else { + format = new DecimalFormat(defaultFormat); + } + + return true; + } + + @Override + protected String[] get(Event e, Number[] source) { + return get(source, new Getter() { + @Override + public String get(Number num) { + return format.format(num); + } + }); + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + public String toString(@Nullable Event e, boolean debug) { + return getExpr().toString(e, debug) + " formatted as " + format.toPattern(); + } + +} From c7b37d8a772bc3fcf160ee7bbcc24d3edc1261a6 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali Date: Tue, 15 Mar 2022 16:01:44 +0300 Subject: [PATCH 02/23] Little changes --- .../ch/njol/skript/expressions/ExprFormatNumber.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java index efb65b9de10..a3ee4e0acf3 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -18,7 +18,6 @@ */ package ch.njol.skript.expressions; -import ch.njol.skript.Metrics; import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; @@ -38,8 +37,10 @@ import java.text.DecimalFormat; @Name("Formatted Number") -@Description("Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') will be used. For reference, see this " - + "article.") +@Description( + "Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') will be used. For reference, see this " + + "article." +) @Examples({ "command /formatnumber :", "\taliases: fn", @@ -57,11 +58,11 @@ public class ExprFormatNumber extends PropertyExpression { "[human-readable] formatted %numbers% [(with|as) %-string%]"); } - @SuppressWarnings("null") + @SuppressWarnings("NotNullFieldNotInitialized") private DecimalFormat format; @Override - @SuppressWarnings("null") + @SuppressWarnings({"null", "unchecked"}) public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { setExpr((Expression) exprs[0]); if (exprs[1] != null) { From cde535cf24d616a2d3b79168fed66a8415cbdbc3 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali Date: Tue, 15 Mar 2022 16:27:17 +0300 Subject: [PATCH 03/23] Prevent variables usage --- .../java/ch/njol/skript/expressions/ExprFormatNumber.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java index a3ee4e0acf3..4b2cd34dbb7 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -54,8 +54,8 @@ public class ExprFormatNumber extends PropertyExpression { static { Skript.registerExpression(ExprFormatNumber.class, String.class, ExpressionType.PROPERTY, - "%numbers% formatted [human-readable] [(with|as) %-string%]", - "[human-readable] formatted %numbers% [(with|as) %-string%]"); + "%numbers% formatted [human-readable] [(with|as) %-*string%]", + "[human-readable] formatted %numbers% [(with|as) %-*string%]"); } @SuppressWarnings("NotNullFieldNotInitialized") From ee12498d033d5063eba0434419aee33f6c07d2c5 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali Date: Wed, 16 Mar 2022 01:14:52 +0300 Subject: [PATCH 04/23] Support variables as custom format --- .../skript/expressions/ExprFormatNumber.java | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java index 4b2cd34dbb7..45b87c4f874 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -54,34 +54,34 @@ public class ExprFormatNumber extends PropertyExpression { static { Skript.registerExpression(ExprFormatNumber.class, String.class, ExpressionType.PROPERTY, - "%numbers% formatted [human-readable] [(with|as) %-*string%]", - "[human-readable] formatted %numbers% [(with|as) %-*string%]"); + "%numbers% formatted [human-readable] [(with|as) %-string%]", + "[human-readable] formatted %numbers% [(with|as) %-string%]"); } @SuppressWarnings("NotNullFieldNotInitialized") private DecimalFormat format; + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression customFormat; + @Override @SuppressWarnings({"null", "unchecked"}) public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { setExpr((Expression) exprs[0]); - if (exprs[1] != null) { - if (!(exprs[1] instanceof Literal)) { - VariableString str = (VariableString) exprs[1]; - if (!str.isSimple()) { - Skript.error("Number format must not contain variables!"); - return false; + customFormat = (Expression) exprs[1]; + + if (customFormat != null) { + if (!(customFormat instanceof Literal) && customFormat instanceof VariableString) { + VariableString str = (VariableString) customFormat; + if (str.isSimple()) { + try { + format = new DecimalFormat(customFormat.getSingle(null)); + } catch (Exception e) { + Skript.error("Incorrect number format used: " + e.getMessage()); + return false; + } } } - String customFormat = (String) exprs[1].getSingle(null); - try { - format = new DecimalFormat(customFormat); - } catch (Exception e) { - Skript.error("Incorrect number format used: " + e.getMessage()); - return false; - } - } else { - format = new DecimalFormat(defaultFormat); } return true; @@ -92,6 +92,15 @@ protected String[] get(Event e, Number[] source) { return get(source, new Getter() { @Override public String get(Number num) { + if (customFormat != null) { + try { + format = new DecimalFormat(customFormat.getSingle(e)); + } catch (Exception ex) { + format = new DecimalFormat(defaultFormat); + } + } else { + format = new DecimalFormat(defaultFormat); + } return format.format(num); } }); @@ -104,7 +113,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event e, boolean debug) { - return getExpr().toString(e, debug) + " formatted as " + format.toPattern(); + return getExpr().toString(e, debug) + " formatted as " + (customFormat != null ? customFormat.toString(e, debug) : defaultFormat); } } From f2348ed3860715a5ca85d1d95313dd3a8010aec6 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali Date: Wed, 16 Mar 2022 18:27:51 +0300 Subject: [PATCH 05/23] Make it return null if format is invalid --- .../skript/expressions/ExprFormatNumber.java | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java index 45b87c4f874..8fe6222d51b 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -70,18 +70,15 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye setExpr((Expression) exprs[0]); customFormat = (Expression) exprs[1]; - if (customFormat != null) { - if (!(customFormat instanceof Literal) && customFormat instanceof VariableString) { - VariableString str = (VariableString) customFormat; - if (str.isSimple()) { - try { - format = new DecimalFormat(customFormat.getSingle(null)); - } catch (Exception e) { - Skript.error("Incorrect number format used: " + e.getMessage()); - return false; - } - } + if (customFormat instanceof Literal || (customFormat instanceof VariableString && ((VariableString) customFormat).isSimple())) { + try { + format = new DecimalFormat(customFormat.getSingle(null)); + } catch (Exception e) { + Skript.error("Incorrect number format used: " + e.getMessage()); + return false; } + } else if (customFormat == null) { + format = new DecimalFormat(defaultFormat); } return true; @@ -92,14 +89,12 @@ protected String[] get(Event e, Number[] source) { return get(source, new Getter() { @Override public String get(Number num) { - if (customFormat != null) { + if (format == null) { try { format = new DecimalFormat(customFormat.getSingle(e)); } catch (Exception ex) { - format = new DecimalFormat(defaultFormat); + return null; } - } else { - format = new DecimalFormat(defaultFormat); } return format.format(num); } From df572d88eb4eb69db952815e279866a6cbbccad0 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali Date: Wed, 16 Mar 2022 18:42:48 +0300 Subject: [PATCH 06/23] Add test script --- .../tests/regressions/4663-formatted numbers.sk | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/skript/tests/regressions/4663-formatted numbers.sk diff --git a/src/test/skript/tests/regressions/4663-formatted numbers.sk b/src/test/skript/tests/regressions/4663-formatted numbers.sk new file mode 100644 index 00000000000..0b3349288be --- /dev/null +++ b/src/test/skript/tests/regressions/4663-formatted numbers.sk @@ -0,0 +1,17 @@ +test "formatted numbers": + set {_num1} to formatted 123456789 + assert {_num1} = "123,456,789" with "default number format failed ##1" + + set {_num2} to 1234567 formatted human-readable + assert {_num2} = "1,234,567" with "default number format failed ##2" + + set {_num3} to formatted 12345678 as "##,##.00" + assert {_num3} = "1,2,3,4,5,6,7,8.00" with "custom number format failed ##1" + + set {_cFormat} to "####,####" + set {_num4} to formatted 12345678 as {_cFormat} + assert {_num4} = "12,34,56,78" with "custom number format failed ##2" + + set {_cFormat2} to "i" + set {_num4} to formatted 12345678 as {_cFormat2} + assert {_num4} is not set with "custom number format failed ##3" From 05307fd0768b3bfafc4937f49048ed1451550089 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali Date: Wed, 16 Mar 2022 18:50:05 +0300 Subject: [PATCH 07/23] Update test script --- src/test/skript/tests/regressions/4663-formatted numbers.sk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/skript/tests/regressions/4663-formatted numbers.sk b/src/test/skript/tests/regressions/4663-formatted numbers.sk index 0b3349288be..97734aaca4b 100644 --- a/src/test/skript/tests/regressions/4663-formatted numbers.sk +++ b/src/test/skript/tests/regressions/4663-formatted numbers.sk @@ -12,6 +12,6 @@ test "formatted numbers": set {_num4} to formatted 12345678 as {_cFormat} assert {_num4} = "12,34,56,78" with "custom number format failed ##2" - set {_cFormat2} to "i" + set {_cFormat2} to "##,.##" set {_num4} to formatted 12345678 as {_cFormat2} assert {_num4} is not set with "custom number format failed ##3" From 66f12a4e7214d228fec2e746fa9263d7e5ebbb28 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali Date: Wed, 16 Mar 2022 19:09:33 +0300 Subject: [PATCH 08/23] Update test script --- src/test/skript/tests/regressions/4663-formatted numbers.sk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/skript/tests/regressions/4663-formatted numbers.sk b/src/test/skript/tests/regressions/4663-formatted numbers.sk index 97734aaca4b..b4aa1fbb61d 100644 --- a/src/test/skript/tests/regressions/4663-formatted numbers.sk +++ b/src/test/skript/tests/regressions/4663-formatted numbers.sk @@ -13,5 +13,5 @@ test "formatted numbers": assert {_num4} = "12,34,56,78" with "custom number format failed ##2" set {_cFormat2} to "##,.##" - set {_num4} to formatted 12345678 as {_cFormat2} - assert {_num4} is not set with "custom number format failed ##3" + set {_num5} to formatted 12345678 as {_cFormat2} + assert {_num5} is not set with "custom number format failed ##3" From 7184c952fa80116ccc310ceacb4159be54f0f22d Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali Date: Thu, 17 Mar 2022 00:57:01 +0300 Subject: [PATCH 09/23] Changes --- .../java/ch/njol/skript/expressions/ExprFormatNumber.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java index 8fe6222d51b..809ce5702ef 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -74,7 +74,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye try { format = new DecimalFormat(customFormat.getSingle(null)); } catch (Exception e) { - Skript.error("Incorrect number format used: " + e.getMessage()); + Skript.error("Invalid number format: " + exprs[1]); return false; } } else if (customFormat == null) { @@ -89,7 +89,7 @@ protected String[] get(Event e, Number[] source) { return get(source, new Getter() { @Override public String get(Number num) { - if (format == null) { + if (customFormat != null) { try { format = new DecimalFormat(customFormat.getSingle(e)); } catch (Exception ex) { From dc61b3984e6d86e096596f9b1b1a964f6f70616f Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 22 Apr 2023 02:13:24 +0300 Subject: [PATCH 10/23] Fix class to use same technique as #4664 --- .../skript/expressions/ExprFormatNumber.java | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java index 809ce5702ef..d19b3ff4d98 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -50,7 +50,7 @@ @Since("INSERT VERSION") public class ExprFormatNumber extends PropertyExpression { - private static final String defaultFormat = "###,###"; + private static final DecimalFormat DEFAULT_FORMAT = new DecimalFormat("###,###"); static { Skript.registerExpression(ExprFormatNumber.class, String.class, ExpressionType.PROPERTY, @@ -70,33 +70,53 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye setExpr((Expression) exprs[0]); customFormat = (Expression) exprs[1]; - if (customFormat instanceof Literal || (customFormat instanceof VariableString && ((VariableString) customFormat).isSimple())) { - try { - format = new DecimalFormat(customFormat.getSingle(null)); - } catch (Exception e) { - Skript.error("Invalid number format: " + exprs[1]); - return false; + boolean isSimpleString = customFormat instanceof VariableString && ((VariableString) customFormat).isSimple(); + if (customFormat instanceof Literal || isSimpleString) { + String customFormatValue; + if (isSimpleString) { + customFormatValue = ((VariableString) customFormat).toString(null); + } else { + customFormatValue = ((Literal) customFormat).getSingle(); + } + + if (customFormatValue != null) { + try { + format = new DecimalFormat(customFormatValue); + } catch (IllegalArgumentException e) { + Skript.error("Invalid number format: " + customFormatValue); + return false; + } } } else if (customFormat == null) { - format = new DecimalFormat(defaultFormat); + format = DEFAULT_FORMAT; } return true; } @Override - protected String[] get(Event e, Number[] source) { + protected String[] get(Event event, Number[] source) { + DecimalFormat format; + String formatString; + + if (customFormat != null && this.format == null) { // customFormat is not Literal or VariableString + formatString = customFormat.getSingle(event); + if (formatString == null) + return null; + + try { + format = new DecimalFormat(formatString); + } catch (IllegalArgumentException e) { + return null; + } + } else { + format = this.format; + } + return get(source, new Getter() { @Override - public String get(Number num) { - if (customFormat != null) { - try { - format = new DecimalFormat(customFormat.getSingle(e)); - } catch (Exception ex) { - return null; - } - } - return format.format(num); + public String get(Number number) { + return format.format(number); } }); } @@ -107,8 +127,8 @@ public Class getReturnType() { } @Override - public String toString(@Nullable Event e, boolean debug) { - return getExpr().toString(e, debug) + " formatted as " + (customFormat != null ? customFormat.toString(e, debug) : defaultFormat); + public String toString(@Nullable Event event, boolean debug) { + return getExpr().toString(event, debug) + " formatted as " + (customFormat != null ? customFormat.toString(event, debug) : DEFAULT_FORMAT.toPattern()); } } From 8654a9478bddb1c9e29f2402ed6740ef46595dc9 Mon Sep 17 00:00:00 2001 From: Ayham Al Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 22 Apr 2023 16:53:31 +0300 Subject: [PATCH 11/23] Apply suggestions from code review Co-authored-by: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> --- .../java/ch/njol/skript/expressions/ExprFormatNumber.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java index d19b3ff4d98..c84e68446c0 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -54,18 +54,18 @@ public class ExprFormatNumber extends PropertyExpression { static { Skript.registerExpression(ExprFormatNumber.class, String.class, ExpressionType.PROPERTY, - "%numbers% formatted [human-readable] [(with|as) %-string%]", - "[human-readable] formatted %numbers% [(with|as) %-string%]"); + "%numbers% formatted [human-readable] [(with|as) %-string%]", + "[human-readable] formatted %numbers% [(with|as) %-string%]"); } @SuppressWarnings("NotNullFieldNotInitialized") private DecimalFormat format; - @SuppressWarnings("NotNullFieldNotInitialized") + @Nullable private Expression customFormat; @Override - @SuppressWarnings({"null", "unchecked"}) + @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { setExpr((Expression) exprs[0]); customFormat = (Expression) exprs[1]; From f30adedb8f03d7ad4abf48d3ab98b39ebe9674f8 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 22 Apr 2023 18:02:03 +0300 Subject: [PATCH 12/23] Add helpful comments and use lambda --- .../njol/skript/expressions/ExprFormatNumber.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java index c84e68446c0..52913123d2a 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -71,6 +71,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye customFormat = (Expression) exprs[1]; boolean isSimpleString = customFormat instanceof VariableString && ((VariableString) customFormat).isSimple(); + // if literal or is simple variable string then we can get the value at init and check if (customFormat instanceof Literal || isSimpleString) { String customFormatValue; if (isSimpleString) { @@ -79,6 +80,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye customFormatValue = ((Literal) customFormat).getSingle(); } + // try to use user provided format if (customFormatValue != null) { try { format = new DecimalFormat(customFormatValue); @@ -87,6 +89,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye return false; } } + // if not set then assign default format } else if (customFormat == null) { format = DEFAULT_FORMAT; } @@ -102,23 +105,18 @@ protected String[] get(Event event, Number[] source) { if (customFormat != null && this.format == null) { // customFormat is not Literal or VariableString formatString = customFormat.getSingle(event); if (formatString == null) - return null; + return new String[0]; try { format = new DecimalFormat(formatString); } catch (IllegalArgumentException e) { - return null; + return new String[0]; } } else { format = this.format; } - return get(source, new Getter() { - @Override - public String get(Number number) { - return format.format(number); - } - }); + return get(source, format::format); } @Override From b4077e866b2ce91290c883cddb4e6e81cccdbd3b Mon Sep 17 00:00:00 2001 From: Ayham Al Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Fri, 15 Mar 2024 18:30:34 +0300 Subject: [PATCH 13/23] Update src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java Co-authored-by: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> --- .../java/ch/njol/skript/expressions/ExprFormatNumber.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java index 52913123d2a..846b4f3d192 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java @@ -38,8 +38,8 @@ @Name("Formatted Number") @Description( - "Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') will be used. For reference, see this " - + "article." + "Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') will be used. For reference, see this " + + "article." ) @Examples({ "command /formatnumber :", From 25d66c1fc7ca8cc928fc2c81bb92c77fb783550d Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 6 Apr 2024 02:00:30 +0300 Subject: [PATCH 14/23] Change expression to function --- .../skript/classes/data/DefaultFunctions.java | 32 +++++ .../skript/expressions/ExprFormatNumber.java | 132 ------------------ 2 files changed, 32 insertions(+), 132 deletions(-) delete mode 100644 src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index d9c16f703af..c3d29592a12 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -20,8 +20,14 @@ import java.math.BigDecimal; import java.math.RoundingMode; +import java.text.DecimalFormat; import java.util.Calendar; +import java.util.regex.Pattern; +import ch.njol.skript.Skript; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.VariableString; import ch.njol.skript.lang.function.FunctionEvent; import ch.njol.skript.lang.function.JavaFunction; import org.bukkit.Bukkit; @@ -48,6 +54,7 @@ public class DefaultFunctions { private static String str(double n) { return StringUtils.toString(n, 4); } + private static final DecimalFormat DEFAULT_FORMAT = new DecimalFormat("###,###"); static { Parameter[] numberParam = new Parameter[] {new Parameter<>("n", DefaultClasses.NUMBER, true, null)}; @@ -471,6 +478,31 @@ public ColorRGB[] executeSimple(Object[][] params) { }).description("Returns a RGB color from the given red, green and blue parameters.") .examples("dye player's leggings rgb(120, 30, 45)") .since("2.5"); + + Functions.registerFunction(new SimpleJavaFunction("formatNumber", new Parameter[] { + new Parameter<>("number", DefaultClasses.NUMBER, true, null), + new Parameter<>("format", DefaultClasses.STRING, true, new SimpleLiteral(DEFAULT_FORMAT.toPattern(), true)) + }, DefaultClasses.STRING, true) { + @Override + public String[] executeSimple(Object[][] params) { + Number number = (Number) params[0][0]; + String pattern = (String) params[1][0]; + + try { + return CollectionUtils.array(new DecimalFormat(pattern).format(number)); + } catch (IllegalArgumentException e) { + Skript.error("Invalid number format: " + pattern); + return new String[0]; + } + } + }).description("Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') will be used. For reference, see this " + + "article.") + .examples( + "command /formatnumber :", + "\taliases: fn", + "\ttrigger:", + "\t\tsend \"Formatted: %formatted arg-1%\" to sender" + ).since("INSERT VERSION"); } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java b/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java deleted file mode 100644 index 846b4f3d192..00000000000 --- a/src/main/java/ch/njol/skript/expressions/ExprFormatNumber.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * This file is part of Skript. - * - * Skript is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Skript is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Skript. If not, see . - * - * Copyright Peter Güttinger, SkriptLang team and contributors - */ -package ch.njol.skript.expressions; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.base.PropertyExpression; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.Literal; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.VariableString; -import ch.njol.skript.util.Getter; -import ch.njol.util.Kleenean; -import org.bukkit.event.Event; -import org.eclipse.jdt.annotation.Nullable; - -import java.text.DecimalFormat; - -@Name("Formatted Number") -@Description( - "Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') will be used. For reference, see this " + - "article." -) -@Examples({ - "command /formatnumber :", - "\taliases: fn", - "\ttrigger:", - "\t\tsend \"Formatted: %formatted arg-1%\" to sender" -}) -@Since("INSERT VERSION") -public class ExprFormatNumber extends PropertyExpression { - - private static final DecimalFormat DEFAULT_FORMAT = new DecimalFormat("###,###"); - - static { - Skript.registerExpression(ExprFormatNumber.class, String.class, ExpressionType.PROPERTY, - "%numbers% formatted [human-readable] [(with|as) %-string%]", - "[human-readable] formatted %numbers% [(with|as) %-string%]"); - } - - @SuppressWarnings("NotNullFieldNotInitialized") - private DecimalFormat format; - - @Nullable - private Expression customFormat; - - @Override - @SuppressWarnings("unchecked") - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - setExpr((Expression) exprs[0]); - customFormat = (Expression) exprs[1]; - - boolean isSimpleString = customFormat instanceof VariableString && ((VariableString) customFormat).isSimple(); - // if literal or is simple variable string then we can get the value at init and check - if (customFormat instanceof Literal || isSimpleString) { - String customFormatValue; - if (isSimpleString) { - customFormatValue = ((VariableString) customFormat).toString(null); - } else { - customFormatValue = ((Literal) customFormat).getSingle(); - } - - // try to use user provided format - if (customFormatValue != null) { - try { - format = new DecimalFormat(customFormatValue); - } catch (IllegalArgumentException e) { - Skript.error("Invalid number format: " + customFormatValue); - return false; - } - } - // if not set then assign default format - } else if (customFormat == null) { - format = DEFAULT_FORMAT; - } - - return true; - } - - @Override - protected String[] get(Event event, Number[] source) { - DecimalFormat format; - String formatString; - - if (customFormat != null && this.format == null) { // customFormat is not Literal or VariableString - formatString = customFormat.getSingle(event); - if (formatString == null) - return new String[0]; - - try { - format = new DecimalFormat(formatString); - } catch (IllegalArgumentException e) { - return new String[0]; - } - } else { - format = this.format; - } - - return get(source, format::format); - } - - @Override - public Class getReturnType() { - return String.class; - } - - @Override - public String toString(@Nullable Event event, boolean debug) { - return getExpr().toString(event, debug) + " formatted as " + (customFormat != null ? customFormat.toString(event, debug) : DEFAULT_FORMAT.toPattern()); - } - -} From ecd4a4a78adf79f0e4a2a817672328325ee00d86 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 6 Apr 2024 02:01:38 +0300 Subject: [PATCH 15/23] Remove unused imports --- .../java/ch/njol/skript/classes/data/DefaultFunctions.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index c3d29592a12..ca8aba0046a 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -22,12 +22,8 @@ import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.Calendar; -import java.util.regex.Pattern; import ch.njol.skript.Skript; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.Literal; -import ch.njol.skript.lang.VariableString; import ch.njol.skript.lang.function.FunctionEvent; import ch.njol.skript.lang.function.JavaFunction; import org.bukkit.Bukkit; From 44889047af4782b8b61e3f18c29c376edd61c721 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 6 Apr 2024 02:07:29 +0300 Subject: [PATCH 16/23] Refactoring and merge base, updating examples --- .../skript/classes/data/DefaultFunctions.java | 15 +++++++-------- .../tests/regressions/4663-formatted numbers.sk | 10 +++++----- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index 4468e5203db..495334e977b 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -18,13 +18,8 @@ */ package ch.njol.skript.classes.data; -import ch.njol.skript.expressions.base.EventValueExpression; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.text.DecimalFormat; -import java.util.Calendar; - import ch.njol.skript.Skript; +import ch.njol.skript.expressions.base.EventValueExpression; import ch.njol.skript.lang.function.FunctionEvent; import ch.njol.skript.lang.function.Functions; import ch.njol.skript.lang.function.JavaFunction; @@ -46,6 +41,10 @@ import org.bukkit.util.Vector; import org.eclipse.jdt.annotation.Nullable; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.util.Calendar; import java.util.UUID; public class DefaultFunctions { @@ -53,7 +52,7 @@ public class DefaultFunctions { private static String str(double n) { return StringUtils.toString(n, 4); } - private static final DecimalFormat DEFAULT_FORMAT = new DecimalFormat("###,###"); + private static final DecimalFormat DEFAULT_NUMBER_FORMAT = new DecimalFormat("###,###"); static { Parameter[] numberParam = new Parameter[] {new Parameter<>("n", DefaultClasses.NUMBER, true, null)}; @@ -575,7 +574,7 @@ public Boolean[] executeSimple(Object[][] params) { Functions.registerFunction(new SimpleJavaFunction("formatNumber", new Parameter[] { new Parameter<>("number", DefaultClasses.NUMBER, true, null), - new Parameter<>("format", DefaultClasses.STRING, true, new SimpleLiteral(DEFAULT_FORMAT.toPattern(), true)) + new Parameter<>("format", DefaultClasses.STRING, true, new SimpleLiteral(DEFAULT_NUMBER_FORMAT.toPattern(), true)) }, DefaultClasses.STRING, true) { @Override public String[] executeSimple(Object[][] params) { diff --git a/src/test/skript/tests/regressions/4663-formatted numbers.sk b/src/test/skript/tests/regressions/4663-formatted numbers.sk index b4aa1fbb61d..a18d8f6551e 100644 --- a/src/test/skript/tests/regressions/4663-formatted numbers.sk +++ b/src/test/skript/tests/regressions/4663-formatted numbers.sk @@ -1,17 +1,17 @@ test "formatted numbers": - set {_num1} to formatted 123456789 + set {_num1} to numberFormat(123456789) assert {_num1} = "123,456,789" with "default number format failed ##1" - set {_num2} to 1234567 formatted human-readable + set {_num2} to numberFormat(1234567) assert {_num2} = "1,234,567" with "default number format failed ##2" - set {_num3} to formatted 12345678 as "##,##.00" + set {_num3} to numberFormat(12345678, "##,##.00") assert {_num3} = "1,2,3,4,5,6,7,8.00" with "custom number format failed ##1" set {_cFormat} to "####,####" - set {_num4} to formatted 12345678 as {_cFormat} + set {_num4} to numberFormat(12345678, {_cFormat}) assert {_num4} = "12,34,56,78" with "custom number format failed ##2" set {_cFormat2} to "##,.##" - set {_num5} to formatted 12345678 as {_cFormat2} + set {_num5} to numberFormat(12345678, {_cFormat2}) assert {_num5} is not set with "custom number format failed ##3" From 664ebf1d0120214cad611c69a4981648aee88a54 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 6 Apr 2024 02:10:06 +0300 Subject: [PATCH 17/23] return null instead of empty string --- src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index 495334e977b..30135f52ea4 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -585,7 +585,7 @@ public String[] executeSimple(Object[][] params) { return CollectionUtils.array(new DecimalFormat(pattern).format(number)); } catch (IllegalArgumentException e) { Skript.error("Invalid number format: " + pattern); - return new String[0]; + return null; } } }).description("Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') will be used. For reference, see this " From 0ce55ab4f10a1069f8b3822246353eca7693aee3 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 6 Apr 2024 02:10:45 +0300 Subject: [PATCH 18/23] Update examples --- src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index 30135f52ea4..89134d20b4e 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -594,7 +594,7 @@ public String[] executeSimple(Object[][] params) { "command /formatnumber :", "\taliases: fn", "\ttrigger:", - "\t\tsend \"Formatted: %formatted arg-1%\" to sender" + "\t\tsend \"Formatted: %numberFormat(arg-1)%\" to sender" ).since("INSERT VERSION"); } From a04f47636489bd09ff7a1d8cabe5da91176196c5 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 6 Apr 2024 02:12:10 +0300 Subject: [PATCH 19/23] Warn instead of erroring, but probably better to remove --- src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index 89134d20b4e..f4a7ef5facb 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -584,7 +584,7 @@ public String[] executeSimple(Object[][] params) { try { return CollectionUtils.array(new DecimalFormat(pattern).format(number)); } catch (IllegalArgumentException e) { - Skript.error("Invalid number format: " + pattern); + Skript.warning("Invalid number format: " + pattern); return null; } } From f238bc0c843e2da0e2e60f9104324ef33285bf65 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 6 Apr 2024 04:41:25 +0300 Subject: [PATCH 20/23] Address reviews --- .../skript/classes/data/DefaultFunctions.java | 19 +++++++++++++------ .../regressions/4663-formatted numbers.sk | 12 ++++++------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index f4a7ef5facb..edb2fed794a 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -18,7 +18,6 @@ */ package ch.njol.skript.classes.data; -import ch.njol.skript.Skript; import ch.njol.skript.expressions.base.EventValueExpression; import ch.njol.skript.lang.function.FunctionEvent; import ch.njol.skript.lang.function.Functions; @@ -52,7 +51,10 @@ public class DefaultFunctions { private static String str(double n) { return StringUtils.toString(n, 4); } - private static final DecimalFormat DEFAULT_NUMBER_FORMAT = new DecimalFormat("###,###"); + private static final String DEFAULT_NUMBER_FORMAT_STRING = "###,###"; + private static final DecimalFormat DEFAULT_NUMBER_FORMAT = new DecimalFormat(DEFAULT_NUMBER_FORMAT_STRING); + private static final ThreadLocal NUMBER_FORMAT = ThreadLocal.withInitial(DecimalFormat::new); + static { Parameter[] numberParam = new Parameter[] {new Parameter<>("n", DefaultClasses.NUMBER, true, null)}; @@ -574,17 +576,22 @@ public Boolean[] executeSimple(Object[][] params) { Functions.registerFunction(new SimpleJavaFunction("formatNumber", new Parameter[] { new Parameter<>("number", DefaultClasses.NUMBER, true, null), - new Parameter<>("format", DefaultClasses.STRING, true, new SimpleLiteral(DEFAULT_NUMBER_FORMAT.toPattern(), true)) + new Parameter<>("format", DefaultClasses.STRING, true, new SimpleLiteral(DEFAULT_NUMBER_FORMAT_STRING, true)) }, DefaultClasses.STRING, true) { @Override public String[] executeSimple(Object[][] params) { Number number = (Number) params[0][0]; String pattern = (String) params[1][0]; + if (DEFAULT_NUMBER_FORMAT_STRING.equals(pattern)) // shortcut + return CollectionUtils.array(DEFAULT_NUMBER_FORMAT.format(number)); + try { - return CollectionUtils.array(new DecimalFormat(pattern).format(number)); + DecimalFormat numberFormat = NUMBER_FORMAT.get(); + numberFormat.applyPattern(pattern); + return CollectionUtils.array(numberFormat.format(number)); } catch (IllegalArgumentException e) { - Skript.warning("Invalid number format: " + pattern); +// Skript.warning("Invalid number format: " + pattern); // TODO find a better solution for such warnings/errors that doesn't spam the console return null; } } @@ -594,7 +601,7 @@ public String[] executeSimple(Object[][] params) { "command /formatnumber :", "\taliases: fn", "\ttrigger:", - "\t\tsend \"Formatted: %numberFormat(arg-1)%\" to sender" + "\t\tsend \"Formatted: %formatNumber(arg-1)%\" to sender" ).since("INSERT VERSION"); } diff --git a/src/test/skript/tests/regressions/4663-formatted numbers.sk b/src/test/skript/tests/regressions/4663-formatted numbers.sk index a18d8f6551e..de4f15af23d 100644 --- a/src/test/skript/tests/regressions/4663-formatted numbers.sk +++ b/src/test/skript/tests/regressions/4663-formatted numbers.sk @@ -1,17 +1,17 @@ -test "formatted numbers": - set {_num1} to numberFormat(123456789) +test "formatted numbers function": + set {_num1} to formatNumber(123456789) assert {_num1} = "123,456,789" with "default number format failed ##1" - set {_num2} to numberFormat(1234567) + set {_num2} to formatNumber(1234567) assert {_num2} = "1,234,567" with "default number format failed ##2" - set {_num3} to numberFormat(12345678, "##,##.00") + set {_num3} to formatNumber(12345678, "##,##.00") assert {_num3} = "1,2,3,4,5,6,7,8.00" with "custom number format failed ##1" set {_cFormat} to "####,####" - set {_num4} to numberFormat(12345678, {_cFormat}) + set {_num4} to formatNumber(12345678, {_cFormat}) assert {_num4} = "12,34,56,78" with "custom number format failed ##2" set {_cFormat2} to "##,.##" - set {_num5} to numberFormat(12345678, {_cFormat2}) + set {_num5} to formatNumber(12345678, {_cFormat2}) assert {_num5} is not set with "custom number format failed ##3" From 80be1e0a057413688acaa6c4ce149f086ab6ecc6 Mon Sep 17 00:00:00 2001 From: Ayham Al-Ali <20037329+AyhamAl-Ali@users.noreply.github.com> Date: Sat, 6 Apr 2024 04:46:10 +0300 Subject: [PATCH 21/23] better variable naming --- .../ch/njol/skript/classes/data/DefaultFunctions.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index edb2fed794a..55b6db32f5e 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -581,17 +581,17 @@ public Boolean[] executeSimple(Object[][] params) { @Override public String[] executeSimple(Object[][] params) { Number number = (Number) params[0][0]; - String pattern = (String) params[1][0]; + String format = (String) params[1][0]; - if (DEFAULT_NUMBER_FORMAT_STRING.equals(pattern)) // shortcut + if (DEFAULT_NUMBER_FORMAT_STRING.equals(format)) // shortcut return CollectionUtils.array(DEFAULT_NUMBER_FORMAT.format(number)); try { DecimalFormat numberFormat = NUMBER_FORMAT.get(); - numberFormat.applyPattern(pattern); + numberFormat.applyPattern(format); return CollectionUtils.array(numberFormat.format(number)); } catch (IllegalArgumentException e) { -// Skript.warning("Invalid number format: " + pattern); // TODO find a better solution for such warnings/errors that doesn't spam the console +// Skript.warning("Invalid number format: " + format); // TODO find a better solution for such warnings/errors that doesn't spam the console return null; } } From 8bfe6c925613d841d784496c57c4f3e0bcd6a260 Mon Sep 17 00:00:00 2001 From: Efnilite <35348263+Efnilite@users.noreply.github.com> Date: Mon, 28 Oct 2024 22:30:15 +0100 Subject: [PATCH 22/23] init commit --- .../skript/classes/data/DefaultFunctions.java | 147 +++++++++--------- .../regressions/4663-formatted numbers.sk | 17 -- .../regressions/9999-formatted numbers.sk | 26 ++++ 3 files changed, 103 insertions(+), 87 deletions(-) delete mode 100644 src/test/skript/tests/regressions/4663-formatted numbers.sk create mode 100644 src/test/skript/tests/regressions/9999-formatted numbers.sk diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index 782f3876480..5c770ca0d5e 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -56,21 +56,20 @@ import java.util.UUID; public class DefaultFunctions { - + private static String str(double n) { return StringUtils.toString(n, 4); } - private static final String DEFAULT_NUMBER_FORMAT_STRING = "###,###"; - private static final DecimalFormat DEFAULT_NUMBER_FORMAT = new DecimalFormat(DEFAULT_NUMBER_FORMAT_STRING); - private static final ThreadLocal NUMBER_FORMAT = ThreadLocal.withInitial(DecimalFormat::new); + private static final DecimalFormat DEFAULT_INTEGER_FORMAT = new DecimalFormat("###,###"); + private static final DecimalFormat DEFAULT_DECIMAL_FORMAT = new DecimalFormat("###,###.##"); static { Parameter[] numberParam = new Parameter[] {new Parameter<>("n", DefaultClasses.NUMBER, true, null)}; Parameter[] numbersParam = new Parameter[] {new Parameter<>("ns", DefaultClasses.NUMBER, false, null)}; - + // basic math functions - + Functions.registerFunction(new SimpleJavaFunction("floor", numberParam, DefaultClasses.LONG, true) { @Override public Long[] executeSimple(Object[][] params) { @@ -81,7 +80,7 @@ public Long[] executeSimple(Object[][] params) { }.description("Rounds a number down, i.e. returns the closest integer smaller than or equal to the argument.") .examples("floor(2.34) = 2", "floor(2) = 2", "floor(2.99) = 2") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("round", new Parameter[] {new Parameter<>("n", DefaultClasses.NUMBER, true, null), new Parameter<>("d", DefaultClasses.NUMBER, true, new SimpleLiteral(0, false))}, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -102,7 +101,7 @@ public Number[] executeSimple(Object[][] params) { }.description("Rounds a number, i.e. returns the closest integer to the argument. Place a second argument to define the decimal placement.") .examples("round(2.34) = 2", "round(2) = 2", "round(2.99) = 3", "round(2.5) = 3") .since("2.2, 2.7 (decimal placement)")); - + Functions.registerFunction(new SimpleJavaFunction("ceil", numberParam, DefaultClasses.LONG, true) { @Override public Long[] executeSimple(Object[][] params) { @@ -113,7 +112,7 @@ public Long[] executeSimple(Object[][] params) { }.description("Rounds a number up, i.e. returns the closest integer larger than or equal to the argument.") .examples("ceil(2.34) = 3", "ceil(2) = 2", "ceil(2.99) = 3") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("ceiling", numberParam, DefaultClasses.LONG, true) { @Override public Long[] executeSimple(Object[][] params) { @@ -124,7 +123,7 @@ public Long[] executeSimple(Object[][] params) { }.description("Alias of ceil.") .examples("ceiling(2.34) = 3", "ceiling(2) = 2", "ceiling(2.99) = 3") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("abs", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -136,7 +135,7 @@ public Number[] executeSimple(Object[][] params) { }.description("Returns the absolute value of the argument, i.e. makes the argument positive.") .examples("abs(3) = 3", "abs(-2) = 2") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("mod", new Parameter[] {new Parameter<>("d", DefaultClasses.NUMBER, true, null), new Parameter<>("m", DefaultClasses.NUMBER, true, null)}, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -151,7 +150,7 @@ public Number[] executeSimple(Object[][] params) { "The returned value is always positive. Returns NaN (not a number) if the second argument is zero.") .examples("mod(3, 2) = 1", "mod(256436, 100) = 36", "mod(-1, 10) = 9") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("exp", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -160,7 +159,7 @@ public Number[] executeSimple(Object[][] params) { }.description("The exponential function. You probably don't need this if you don't know what this is.") .examples("exp(0) = 1", "exp(1) = " + str(Math.exp(1))) .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("ln", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -170,7 +169,7 @@ public Number[] executeSimple(Object[][] params) { "Returns NaN (not a number) if the argument is negative.") .examples("ln(1) = 0", "ln(exp(5)) = 5", "ln(2) = " + StringUtils.toString(Math.log(2), 4)) .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("log", new Parameter[] {new Parameter<>("n", DefaultClasses.NUMBER, true, null), new Parameter<>("base", DefaultClasses.NUMBER, true, new SimpleLiteral(10, false))}, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -182,7 +181,7 @@ public Number[] executeSimple(Object[][] params) { "Returns NaN (not a number) if any of the arguments are negative.") .examples("log(100) = 2 # 10^2 = 100", "log(16, 2) = 4 # 2^4 = 16") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("sqrt", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -192,9 +191,9 @@ public Number[] executeSimple(Object[][] params) { "Returns NaN (not a number) if the argument is negative.") .examples("sqrt(4) = 2", "sqrt(2) = " + str(Math.sqrt(2)), "sqrt(-1) = " + str(Math.sqrt(-1))) .since("2.2")); - + // trigonometry - + Functions.registerFunction(new SimpleJavaFunction("sin", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -203,7 +202,7 @@ public Number[] executeSimple(Object[][] params) { }.description("The sine function. It starts at 0° with a value of 0, goes to 1 at 90°, back to 0 at 180°, to -1 at 270° and then repeats every 360°. Uses degrees, not radians.") .examples("sin(90) = 1", "sin(60) = " + str(Math.sin(Math.toRadians(60)))) .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("cos", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -212,7 +211,7 @@ public Number[] executeSimple(Object[][] params) { }.description("The cosine function. This is basically the sine shifted by 90°, i.e. cos(a) = sin(a + 90°), for any number a. Uses degrees, not radians.") .examples("cos(0) = 1", "cos(90) = 0") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("tan", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -221,7 +220,7 @@ public Number[] executeSimple(Object[][] params) { }.description("The tangent function. This is basically sin(arg)/cos(arg). Uses degrees, not radians.") .examples("tan(0) = 0", "tan(45) = 1", "tan(89.99) = " + str(Math.tan(Math.toRadians(89.99)))) .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("asin", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -230,7 +229,7 @@ public Number[] executeSimple(Object[][] params) { }.description("The inverse of the sine, also called arcsin. Returns result in degrees, not radians. Only returns values from -90 to 90.") .examples("asin(0) = 0", "asin(1) = 90", "asin(0.5) = " + str(Math.toDegrees(Math.asin(0.5)))) .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("acos", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -239,7 +238,7 @@ public Number[] executeSimple(Object[][] params) { }.description("The inverse of the cosine, also called arccos. Returns result in degrees, not radians. Only returns values from 0 to 180.") .examples("acos(0) = 90", "acos(1) = 0", "acos(0.5) = " + str(Math.toDegrees(Math.asin(0.5)))) .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("atan", numberParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -248,7 +247,7 @@ public Number[] executeSimple(Object[][] params) { }.description("The inverse of the tangent, also called arctan. Returns result in degrees, not radians. Only returns values from -90 to 90.") .examples("atan(0) = 0", "atan(1) = 45", "atan(10000) = " + str(Math.toDegrees(Math.atan(10000)))) .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("atan2", new Parameter[] { new Parameter<>("x", DefaultClasses.NUMBER, true, null), new Parameter<>("y", DefaultClasses.NUMBER, true, null) @@ -261,9 +260,9 @@ public Number[] executeSimple(Object[][] params) { "The returned angle is measured counterclockwise in a standard mathematical coordinate system (x to the right, y to the top).") .examples("atan2(0, 1) = 0", "atan2(10, 0) = 90", "atan2(-10, 5) = " + str(Math.toDegrees(Math.atan2(-10, 5)))) .since("2.2")); - + // more stuff - + Functions.registerFunction(new SimpleJavaFunction("sum", numbersParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -276,7 +275,7 @@ public Number[] executeSimple(Object[][] params) { }.description("Sums a list of numbers.") .examples("sum(1) = 1", "sum(2, 3, 4) = 9", "sum({some list variable::*})", "sum(2, {_v::*}, and the player's y-coordinate)") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("product", numbersParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -289,7 +288,7 @@ public Number[] executeSimple(Object[][] params) { }.description("Calculates the product of a list of numbers.") .examples("product(1) = 1", "product(2, 3, 4) = 24", "product({some list variable::*})", "product(2, {_v::*}, and the player's y-coordinate)") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("max", numbersParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -305,7 +304,7 @@ public Number[] executeSimple(Object[][] params) { }.description("Returns the maximum number from a list of numbers.") .examples("max(1) = 1", "max(1, 2, 3, 4) = 4", "max({some list variable::*})") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("min", numbersParam, DefaultClasses.NUMBER, true) { @Override public Number[] executeSimple(Object[][] params) { @@ -364,7 +363,7 @@ public Class getReturnType(Expression... arguments) { .since("2.8.0"); // misc - + Functions.registerFunction(new SimpleJavaFunction("world", new Parameter[] { new Parameter<>("name", DefaultClasses.STRING, true, null) }, DefaultClasses.WORLD, true) { @@ -424,7 +423,7 @@ public Location[] execute(FunctionEvent event, Object[][] params) { "delete all entities in radius 25 around location(50,50,50, world \"world_nether\")", "ignite all entities in radius 25 around location(1,1,1, world of player)") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("date", new Parameter[] { new Parameter<>("year", DefaultClasses.NUMBER, true, null), new Parameter<>("month", DefaultClasses.NUMBER, true, null), @@ -457,7 +456,7 @@ public Location[] execute(FunctionEvent event, Object[][] params) { 0, 0, 0 }; - + { int length = getSignature().getMaxParameters(); assert fields.length == length @@ -465,7 +464,7 @@ public Location[] execute(FunctionEvent event, Object[][] params) { && scale.length == length && relations.length == length; } - + @Override public Date[] executeSimple(Object[][] params) { Calendar c = Calendar.getInstance(); @@ -474,21 +473,21 @@ public Date[] executeSimple(Object[][] params) { for (int i = 0; i < fields.length; i++) { int field = fields[i]; Number n = (Number) params[i][0]; - + double value = n.doubleValue() * scale[i] + offsets[i] + carry; int v = (int) Math2.floor(value); carry = (value - v) * relations[i]; //noinspection MagicConstant c.set(field, v); } - + return new Date[] {new Date(c.getTimeInMillis(), c.getTimeZone())}; } }.description("Creates a date from a year, month, and day, and optionally also from hour, minute, second and millisecond.", "A time zone and DST offset can be specified as well (in minutes), if they are left out the server's time zone and DST offset are used (the created date will not retain this information).") .examples("date(2014, 10, 1) # 0:00, 1st October 2014", "date(1990, 3, 5, 14, 30) # 14:30, 5th May 1990", "date(1999, 12, 31, 23, 59, 59, 999, -3*60, 0) # almost year 2000 in parts of Brazil (-3 hours offset, no DST)") .since("2.2")); - + Functions.registerFunction(new SimpleJavaFunction("vector", new Parameter[] { new Parameter<>("x", DefaultClasses.NUMBER, true, null), new Parameter<>("y", DefaultClasses.NUMBER, true, null), @@ -502,11 +501,11 @@ public Vector[] executeSimple(Object[][] params) { ((Number)params[2][0]).doubleValue() )}; } - + }.description("Creates a new vector, which can be used with various expressions, effects and functions.") .examples("vector(0, 0, 0)") .since("2.2-dev23")); - + Functions.registerFunction(new SimpleJavaFunction("calcExperience", new Parameter[] { new Parameter<>("level", DefaultClasses.LONG, true, null) }, DefaultClasses.LONG, true) { @@ -523,13 +522,13 @@ public Long[] executeSimple(Object[][] params) { } else { // Half experience points do not exist, anyway exp = (int) (4.5 * level * level - 162.5 * level + 2220); } - + return new Long[] {exp}; } - + }.description("Calculates the total amount of experience needed to achieve given level from scratch in Minecraft.") .since("2.2-dev32")); - + Functions.registerFunction(new SimpleJavaFunction("rgb", new Parameter[] { new Parameter<>("red", DefaultClasses.LONG, true, null), new Parameter<>("green", DefaultClasses.LONG, true, null), @@ -631,36 +630,6 @@ public Boolean[] executeSimple(Object[][] params) { .examples("isNaN(0) # false", "isNaN(0/0) # true", "isNaN(sqrt(-1)) # true") .since("2.8.0"); - Functions.registerFunction(new SimpleJavaFunction("formatNumber", new Parameter[] { - new Parameter<>("number", DefaultClasses.NUMBER, true, null), - new Parameter<>("format", DefaultClasses.STRING, true, new SimpleLiteral(DEFAULT_NUMBER_FORMAT_STRING, true)) - }, DefaultClasses.STRING, true) { - @Override - public String[] executeSimple(Object[][] params) { - Number number = (Number) params[0][0]; - String format = (String) params[1][0]; - - if (DEFAULT_NUMBER_FORMAT_STRING.equals(format)) // shortcut - return CollectionUtils.array(DEFAULT_NUMBER_FORMAT.format(number)); - - try { - DecimalFormat numberFormat = NUMBER_FORMAT.get(); - numberFormat.applyPattern(format); - return CollectionUtils.array(numberFormat.format(number)); - } catch (IllegalArgumentException e) { -// Skript.warning("Invalid number format: " + format); // TODO find a better solution for such warnings/errors that doesn't spam the console - return null; - } - } - }).description("Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') will be used. For reference, see this " - + "article.") - .examples( - "command /formatnumber :", - "\taliases: fn", - "\ttrigger:", - "\t\tsend \"Formatted: %formatNumber(arg-1)%\" to sender" - ).since("INSERT VERSION"); - Functions.registerFunction(new SimpleJavaFunction("concat", new Parameter[] { new Parameter<>("texts", DefaultClasses.OBJECT, false, null) }, DefaultClasses.STRING, true) { @@ -722,6 +691,44 @@ public Quaternionf[] executeSimple(Object[][] params) { } } // end joml functions + Functions.registerFunction(new SimpleJavaFunction<>("formatNumber", new Parameter[]{ + new Parameter<>("number", DefaultClasses.NUMBER, true, null), + new Parameter<>("format", DefaultClasses.STRING, true, new SimpleLiteral<>("", true)) + }, DefaultClasses.STRING, true) { + @Override + public String[] executeSimple(Object[][] params) { + Number number = (Number) params[0][0]; + String format = (String) params[1][0]; + + if (format.isEmpty()) { + if (number instanceof Double || number instanceof Float) { + return new String[]{DEFAULT_DECIMAL_FORMAT.format(number)}; + } else { + return new String[]{DEFAULT_INTEGER_FORMAT.format(number)}; + } + } + + try { + return new String[]{new DecimalFormat(format).format(number)}; + } catch (IllegalArgumentException e) { + return null; // invalid format + } + } + }) + .description( + "Converts numbers to human-readable format. By default, '###,###' (e.g. '123,456,789') " + + "will be used for whole numbers and '###,###.##' (e.g. '123,456,789.00) will be used for decimal numbers. " + + "A hashtag '#' represents a digit, a comma ',' is used to separate numbers, and a period '.' is used for decimals. ", + "Will return none if the format is invalid.", + "For further reference, see this article.") + .examples( + "command /balance:", + "\taliases: bal", + "\texecutable by: players", + "\ttrigger:", + "\t\tset {_money} to formatNumber({money::%sender's uuid%})", + "\t\tsend \"Your balance: %{_money}%\" to sender") + .since("INSERT VERSION"); } } diff --git a/src/test/skript/tests/regressions/4663-formatted numbers.sk b/src/test/skript/tests/regressions/4663-formatted numbers.sk deleted file mode 100644 index de4f15af23d..00000000000 --- a/src/test/skript/tests/regressions/4663-formatted numbers.sk +++ /dev/null @@ -1,17 +0,0 @@ -test "formatted numbers function": - set {_num1} to formatNumber(123456789) - assert {_num1} = "123,456,789" with "default number format failed ##1" - - set {_num2} to formatNumber(1234567) - assert {_num2} = "1,234,567" with "default number format failed ##2" - - set {_num3} to formatNumber(12345678, "##,##.00") - assert {_num3} = "1,2,3,4,5,6,7,8.00" with "custom number format failed ##1" - - set {_cFormat} to "####,####" - set {_num4} to formatNumber(12345678, {_cFormat}) - assert {_num4} = "12,34,56,78" with "custom number format failed ##2" - - set {_cFormat2} to "##,.##" - set {_num5} to formatNumber(12345678, {_cFormat2}) - assert {_num5} is not set with "custom number format failed ##3" diff --git a/src/test/skript/tests/regressions/9999-formatted numbers.sk b/src/test/skript/tests/regressions/9999-formatted numbers.sk new file mode 100644 index 00000000000..9bbba8a3da8 --- /dev/null +++ b/src/test/skript/tests/regressions/9999-formatted numbers.sk @@ -0,0 +1,26 @@ +test "formatted numbers function": + assert formatNumber(123456789) is "123,456,789" with "default number format failed ##1" + assert formatNumber(1234567) is "1,234,567" with "default number format failed ##2" + assert formatNumber(123.456) is "123.46" with "default number format failed ##3" + + assert formatNumber(12345678, "##,##.00") is "12,34,56,78.00" with "custom number format failed ##1" + assert formatNumber(12345678, "####,####") is "1234,5678" with "custom number format failed ##2" + assert formatNumber(123456.789, "$###,###.##") is "$123,456.79" with "custom number format failed ##3" + + assert formatNumber(12345678, "##.,##") is not set with "invalid number format returns a value" + assert formatNumber(123.45678, "##.,##") is not set with "invalid number format returns a value" + + set {_n} to "a" parsed as number + assert formatNumber({_n}) is not set with "invalid number returns a value" + assert formatNumber({_n}, "##,##") is not set with "invalid number with format returns a value" + assert formatNumber({_n}, "##.,##") is not set with "invalid number with invalid format returns a value" + + set {_n} to NaN value + assert formatNumber({_n}) is "NaN" with "NaN doesn't return a value" + assert formatNumber({_n}, "##,##") is "NaN" with "NaN with format doesn't return a value" + assert formatNumber({_n}, "##.,##") is not set with "NaN with invalid format returns a value" + + set {_n} to infinity value + assert formatNumber({_n}) is "∞" with "infinity doesn't return a value" + assert formatNumber({_n}, "##,##") is "∞" with "infinity with format doesn't return a value" + assert formatNumber({_n}, "##.,##") is not set with "infinity with invalid format returns a value" From 83a412abc2d97b4c8918330a778b23f5583aeadf Mon Sep 17 00:00:00 2001 From: Efnilite <35348263+Efnilite@users.noreply.github.com> Date: Mon, 28 Oct 2024 22:36:34 +0100 Subject: [PATCH 23/23] update file name --- .../{9999-formatted numbers.sk => 7166-formatted numbers.sk} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/skript/tests/regressions/{9999-formatted numbers.sk => 7166-formatted numbers.sk} (100%) diff --git a/src/test/skript/tests/regressions/9999-formatted numbers.sk b/src/test/skript/tests/regressions/7166-formatted numbers.sk similarity index 100% rename from src/test/skript/tests/regressions/9999-formatted numbers.sk rename to src/test/skript/tests/regressions/7166-formatted numbers.sk