From 4687117f33d47a2e1bbcb9c3f95fff5248f0e801 Mon Sep 17 00:00:00 2001 From: Moderocky Date: Sat, 18 Jan 2025 12:58:31 +0000 Subject: [PATCH 1/3] Add example annotation. --- src/main/java/ch/njol/skript/doc/Example.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/main/java/ch/njol/skript/doc/Example.java diff --git a/src/main/java/ch/njol/skript/doc/Example.java b/src/main/java/ch/njol/skript/doc/Example.java new file mode 100644 index 00000000000..5e0725016eb --- /dev/null +++ b/src/main/java/ch/njol/skript/doc/Example.java @@ -0,0 +1,51 @@ +package ch.njol.skript.doc; + +import java.lang.annotation.*; + + +/** + * An example to be used in documentation for the annotated element. + * Multiple example annotations can be stacked on a single syntax element. + *

+ * Each annotation should include a single example. + * This can be used instead of the existing {@link ch.njol.skript.doc.Examples} annotation. + *

+ * Multi-line examples should use multi-line strings. + * Note that whitespace and quotes do not need to be escaped in this mode. + * The indentation will start from the least-indented line (and most IDEs provide a guideline to show this). + *

{@code
+ * @Example("set player's health to 1")
+ * @Example("""
+ * 		if player's health is greater than 10:
+ * 			send "Wow you're really healthy!"
+ * 		""")
+ * @Example("""
+ * 		# sets the player's health to 1
+ * 		set player's health to 1""")
+ * public class MyExpression extends ... {
+ * }
+ * }
+ */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(Example.Examples.class) +@Documented +public @interface Example { + + String value(); + + boolean inTrigger() default true; // todo needed? + + /** + * The internal container annotation for multiple examples. + */ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @interface Examples { + + Example[] value(); + + } + +} From 4a9d0a155bbf5bfb53d1f0f7c0828c4d5f5512e7 Mon Sep 17 00:00:00 2001 From: Moderocky Date: Sat, 18 Jan 2025 13:04:42 +0000 Subject: [PATCH 2/3] Support new annotation in documentation generators. --- .../ch/njol/skript/doc/Documentation.java | 7 +++- .../ch/njol/skript/doc/HTMLGenerator.java | 36 +++++++++++++------ .../ch/njol/skript/doc/JSONGenerator.java | 17 +++++++-- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/main/java/ch/njol/skript/doc/Documentation.java b/src/main/java/ch/njol/skript/doc/Documentation.java index d1509f84a42..66386594cfc 100644 --- a/src/main/java/ch/njol/skript/doc/Documentation.java +++ b/src/main/java/ch/njol/skript/doc/Documentation.java @@ -286,7 +286,12 @@ private static void insertSyntaxElement(final PrintWriter pw, final SyntaxElemen Class elementClass = info.getElementClass(); if (elementClass.getAnnotation(NoDoc.class) != null) return; - if (elementClass.getAnnotation(Name.class) == null || elementClass.getAnnotation(Description.class) == null || elementClass.getAnnotation(Examples.class) == null || elementClass.getAnnotation(Since.class) == null) { + if (elementClass.getAnnotation(Name.class) == null + || elementClass.getAnnotation(Description.class) == null + || (!elementClass.isAnnotationPresent(Examples.class) + && !elementClass.isAnnotationPresent(Example.class) + && !elementClass.isAnnotationPresent(Example.Examples.class)) + || elementClass.getAnnotation(Since.class) == null) { Skript.warning("" + elementClass.getSimpleName() + " is missing information"); return; } diff --git a/src/main/java/ch/njol/skript/doc/HTMLGenerator.java b/src/main/java/ch/njol/skript/doc/HTMLGenerator.java index 63dbb2900a4..742026b8fa3 100644 --- a/src/main/java/ch/njol/skript/doc/HTMLGenerator.java +++ b/src/main/java/ch/njol/skript/doc/HTMLGenerator.java @@ -20,6 +20,7 @@ import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.block.BlockCanBuildEvent; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.lang.entry.EntryData; import org.skriptlang.skript.lang.entry.EntryValidator; @@ -29,12 +30,7 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; +import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -438,10 +434,7 @@ private String generateAnnotated(String descTemp, SyntaxElementInfo info, @Nu .replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " ")); // Examples - Examples examples = c.getAnnotation(Examples.class); - desc = desc.replace("${element.examples}", Joiner.on("
").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples.value()) : null), "Missing examples."))); - desc = desc.replace("${element.examples-safe}", Joiner.on("
").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples.value()) : null), "Missing examples.")) - .replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " ")); + desc = extractExamples(desc, c); // Documentation ID desc = desc.replace("${element.id}", DocumentationIdProvider.getId(info)); @@ -542,6 +535,29 @@ private String generateAnnotated(String descTemp, SyntaxElementInfo info, @Nu return desc; } + private @NotNull String extractExamples(String desc, Class syntax) { + if (syntax.isAnnotationPresent(Example.class)) { + Example examples = syntax.getAnnotation(Example.class); + return this.addExamples(desc, examples.value()); + } else if (syntax.isAnnotationPresent(Example.Examples.class)) { + Example.Examples examples = syntax.getAnnotation(Example.Examples.class); + return this.addExamples(desc, Arrays.stream(examples.value()) + .map(Example::value).toArray(String[]::new)); + } else if (syntax.isAnnotationPresent(Examples.class)) { + Examples examples = syntax.getAnnotation(Examples.class); + return this.addExamples(desc, examples.value()); + } else { + return this.addExamples(desc, (String[]) null); + } + } + + private @NotNull String addExamples(String desc, String @Nullable ... examples) { + desc = desc.replace("${element.examples}", Joiner.on("
").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples) : null), "Missing examples."))); + desc = desc.replace("${element.examples-safe}", Joiner.on("
").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples) : null), "Missing examples.")) + .replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " ")); + return desc; + } + private String generateEvent(String descTemp, SkriptEventInfo info, @Nullable String page) { Class c = info.getElementClass(); String desc; diff --git a/src/main/java/ch/njol/skript/doc/JSONGenerator.java b/src/main/java/ch/njol/skript/doc/JSONGenerator.java index f8c9827474e..0ef57d40822 100644 --- a/src/main/java/ch/njol/skript/doc/JSONGenerator.java +++ b/src/main/java/ch/njol/skript/doc/JSONGenerator.java @@ -13,6 +13,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.lang.structure.Structure; import org.skriptlang.skript.lang.structure.StructureInfo; @@ -21,6 +22,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.Iterator; import java.util.Objects; import java.util.stream.Stream; @@ -39,7 +41,7 @@ public JSONGenerator(File templateDir, File outputDir) { * @param strings the String array to convert * @return the JsonArray containing the Strings */ - private static @Nullable JsonArray convertToJsonArray(String @Nullable [] strings) { + private static @Nullable JsonArray convertToJsonArray(String @Nullable ... strings) { if (strings == null) return null; JsonArray jsonArray = new JsonArray(); @@ -73,9 +75,18 @@ public JSONGenerator(File templateDir, File outputDir) { syntaxJsonObject.add("description", new JsonArray()); } - Examples examplesAnnotation = syntaxClass.getAnnotation(Examples.class); - if (examplesAnnotation != null) { + if (syntaxClass.isAnnotationPresent(Examples.class)) { + @NotNull Examples examplesAnnotation = syntaxClass.getAnnotation(Examples.class); syntaxJsonObject.add("examples", convertToJsonArray(examplesAnnotation.value())); + } else if (syntaxClass.isAnnotationPresent(Example.Examples.class)) { + // If there are multiple examples, they get containerised + @NotNull Example.Examples examplesAnnotation = syntaxClass.getAnnotation(Example.Examples.class); + syntaxJsonObject.add("examples", convertToJsonArray(Arrays.stream(examplesAnnotation.value()) + .map(Example::value).toArray(String[]::new))); + } else if (syntaxClass.isAnnotationPresent(Example.class)) { + // If the user adds just one example, it isn't containerised + @NotNull Example example = syntaxClass.getAnnotation(Example.class); + syntaxJsonObject.add("examples", convertToJsonArray(example.value())); } else { syntaxJsonObject.add("examples", new JsonArray()); } From 340c528fa23aaddb0591a912b00b7f78b1a08d69 Mon Sep 17 00:00:00 2001 From: Moderocky Date: Thu, 23 Jan 2025 11:13:02 +0000 Subject: [PATCH 3/3] Update src/main/java/ch/njol/skript/doc/Example.java Co-authored-by: Efnilite <35348263+Efnilite@users.noreply.github.com> --- src/main/java/ch/njol/skript/doc/Example.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ch/njol/skript/doc/Example.java b/src/main/java/ch/njol/skript/doc/Example.java index 5e0725016eb..31934380c25 100644 --- a/src/main/java/ch/njol/skript/doc/Example.java +++ b/src/main/java/ch/njol/skript/doc/Example.java @@ -2,7 +2,6 @@ import java.lang.annotation.*; - /** * An example to be used in documentation for the annotated element. * Multiple example annotations can be stacked on a single syntax element.