Skip to content

Commit 20b8f2a

Browse files
authored
Documentation annotations improvements (Prototype). (#7470)
* Add example annotation. * Support new annotation in documentation generators. * Update src/main/java/ch/njol/skript/doc/Example.java
1 parent 913a7d8 commit 20b8f2a

File tree

4 files changed

+95
-8
lines changed

4 files changed

+95
-8
lines changed

src/main/java/ch/njol/skript/doc/Documentation.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,12 @@ private static void insertSyntaxElement(final PrintWriter pw, final SyntaxElemen
286286
Class<?> elementClass = info.getElementClass();
287287
if (elementClass.getAnnotation(NoDoc.class) != null)
288288
return;
289-
if (elementClass.getAnnotation(Name.class) == null || elementClass.getAnnotation(Description.class) == null || elementClass.getAnnotation(Examples.class) == null || elementClass.getAnnotation(Since.class) == null) {
289+
if (elementClass.getAnnotation(Name.class) == null
290+
|| elementClass.getAnnotation(Description.class) == null
291+
|| (!elementClass.isAnnotationPresent(Examples.class)
292+
&& !elementClass.isAnnotationPresent(Example.class)
293+
&& !elementClass.isAnnotationPresent(Example.Examples.class))
294+
|| elementClass.getAnnotation(Since.class) == null) {
290295
Skript.warning("" + elementClass.getSimpleName() + " is missing information");
291296
return;
292297
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package ch.njol.skript.doc;
2+
3+
import java.lang.annotation.*;
4+
5+
/**
6+
* An example to be used in documentation for the annotated element.
7+
* Multiple example annotations can be stacked on a single syntax element.
8+
* <p>
9+
* Each annotation should include a single example.
10+
* This can be used instead of the existing {@link ch.njol.skript.doc.Examples} annotation.
11+
* <p>
12+
* <b>Multi-line examples</b> should use multi-line strings.
13+
* Note that whitespace and quotes do not need to be escaped in this mode.
14+
* The indentation will start from the least-indented line (and most IDEs provide a guideline to show this).
15+
* <pre>{@code
16+
* @Example("set player's health to 1")
17+
* @Example("""
18+
* if player's health is greater than 10:
19+
* send "Wow you're really healthy!"
20+
* """)
21+
* @Example("""
22+
* # sets the player's health to 1
23+
* set player's health to 1""")
24+
* public class MyExpression extends ... {
25+
* }
26+
* }</pre>
27+
*/
28+
@Target(ElementType.TYPE)
29+
@Retention(RetentionPolicy.RUNTIME)
30+
@Repeatable(Example.Examples.class)
31+
@Documented
32+
public @interface Example {
33+
34+
String value();
35+
36+
boolean inTrigger() default true; // todo needed?
37+
38+
/**
39+
* The internal container annotation for multiple examples.
40+
*/
41+
@Target(ElementType.TYPE)
42+
@Retention(RetentionPolicy.RUNTIME)
43+
@Documented
44+
@interface Examples {
45+
46+
Example[] value();
47+
48+
}
49+
50+
}

src/main/java/ch/njol/skript/doc/HTMLGenerator.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.bukkit.event.Cancellable;
2121
import org.bukkit.event.Event;
2222
import org.bukkit.event.block.BlockCanBuildEvent;
23+
import org.jetbrains.annotations.NotNull;
2324
import org.jetbrains.annotations.Nullable;
2425
import org.skriptlang.skript.lang.entry.EntryData;
2526
import org.skriptlang.skript.lang.entry.EntryValidator;
@@ -442,10 +443,7 @@ private String generateAnnotated(String descTemp, SyntaxElementInfo<?> info, @Nu
442443
.replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " "));
443444

444445
// Examples
445-
Examples examples = c.getAnnotation(Examples.class);
446-
desc = desc.replace("${element.examples}", Joiner.on("<br>").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples.value()) : null), "Missing examples.")));
447-
desc = desc.replace("${element.examples-safe}", Joiner.on("<br>").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples.value()) : null), "Missing examples."))
448-
.replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " "));
446+
desc = extractExamples(desc, c);
449447

450448
// Documentation ID
451449
desc = desc.replace("${element.id}", DocumentationIdProvider.getId(info));
@@ -546,6 +544,29 @@ private String generateAnnotated(String descTemp, SyntaxElementInfo<?> info, @Nu
546544
return desc;
547545
}
548546

547+
private @NotNull String extractExamples(String desc, Class<?> syntax) {
548+
if (syntax.isAnnotationPresent(Example.class)) {
549+
Example examples = syntax.getAnnotation(Example.class);
550+
return this.addExamples(desc, examples.value());
551+
} else if (syntax.isAnnotationPresent(Example.Examples.class)) {
552+
Example.Examples examples = syntax.getAnnotation(Example.Examples.class);
553+
return this.addExamples(desc, Arrays.stream(examples.value())
554+
.map(Example::value).toArray(String[]::new));
555+
} else if (syntax.isAnnotationPresent(Examples.class)) {
556+
Examples examples = syntax.getAnnotation(Examples.class);
557+
return this.addExamples(desc, examples.value());
558+
} else {
559+
return this.addExamples(desc, (String[]) null);
560+
}
561+
}
562+
563+
private @NotNull String addExamples(String desc, String @Nullable ... examples) {
564+
desc = desc.replace("${element.examples}", Joiner.on("<br>").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples) : null), "Missing examples.")));
565+
desc = desc.replace("${element.examples-safe}", Joiner.on("<br>").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples) : null), "Missing examples."))
566+
.replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", " "));
567+
return desc;
568+
}
569+
549570
private String generateEvent(String descTemp, SkriptEventInfo<?> info, @Nullable String page) {
550571
Class<?> c = info.getElementClass();
551572
String desc;

src/main/java/ch/njol/skript/doc/JSONGenerator.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.google.gson.JsonArray;
1414
import com.google.gson.JsonObject;
1515
import com.google.gson.JsonPrimitive;
16+
import org.jetbrains.annotations.NotNull;
1617
import org.jetbrains.annotations.Nullable;
1718
import org.skriptlang.skript.lang.structure.Structure;
1819
import org.skriptlang.skript.lang.structure.StructureInfo;
@@ -21,6 +22,7 @@
2122
import java.io.IOException;
2223
import java.nio.file.Files;
2324
import java.nio.file.Path;
25+
import java.util.Arrays;
2426
import java.util.Iterator;
2527
import java.util.Objects;
2628
import java.util.stream.Stream;
@@ -39,7 +41,7 @@ public JSONGenerator(File templateDir, File outputDir) {
3941
* @param strings the String array to convert
4042
* @return the JsonArray containing the Strings
4143
*/
42-
private static @Nullable JsonArray convertToJsonArray(String @Nullable [] strings) {
44+
private static @Nullable JsonArray convertToJsonArray(String @Nullable ... strings) {
4345
if (strings == null)
4446
return null;
4547
JsonArray jsonArray = new JsonArray();
@@ -73,9 +75,18 @@ public JSONGenerator(File templateDir, File outputDir) {
7375
syntaxJsonObject.add("description", new JsonArray());
7476
}
7577

76-
Examples examplesAnnotation = syntaxClass.getAnnotation(Examples.class);
77-
if (examplesAnnotation != null) {
78+
if (syntaxClass.isAnnotationPresent(Examples.class)) {
79+
@NotNull Examples examplesAnnotation = syntaxClass.getAnnotation(Examples.class);
7880
syntaxJsonObject.add("examples", convertToJsonArray(examplesAnnotation.value()));
81+
} else if (syntaxClass.isAnnotationPresent(Example.Examples.class)) {
82+
// If there are multiple examples, they get containerised
83+
@NotNull Example.Examples examplesAnnotation = syntaxClass.getAnnotation(Example.Examples.class);
84+
syntaxJsonObject.add("examples", convertToJsonArray(Arrays.stream(examplesAnnotation.value())
85+
.map(Example::value).toArray(String[]::new)));
86+
} else if (syntaxClass.isAnnotationPresent(Example.class)) {
87+
// If the user adds just one example, it isn't containerised
88+
@NotNull Example example = syntaxClass.getAnnotation(Example.class);
89+
syntaxJsonObject.add("examples", convertToJsonArray(example.value()));
7990
} else {
8091
syntaxJsonObject.add("examples", new JsonArray());
8192
}

0 commit comments

Comments
 (0)