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/Example.java b/src/main/java/ch/njol/skript/doc/Example.java
new file mode 100644
index 00000000000..31934380c25
--- /dev/null
+++ b/src/main/java/ch/njol/skript/doc/Example.java
@@ -0,0 +1,50 @@
+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();
+
+ }
+
+}
diff --git a/src/main/java/ch/njol/skript/doc/HTMLGenerator.java b/src/main/java/ch/njol/skript/doc/HTMLGenerator.java
index a2ef14fce7e..15a179a2594 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;
@@ -442,10 +443,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));
@@ -546,6 +544,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());
}