Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation annotations improvements (Prototype). #7470

Open
wants to merge 4 commits into
base: dev/patch
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/main/java/ch/njol/skript/doc/Documentation.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/ch/njol/skript/doc/Example.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package ch.njol.skript.doc;

import java.lang.annotation.*;

/**
Moderocky marked this conversation as resolved.
Show resolved Hide resolved
* An example to be used in documentation for the annotated element.
* Multiple example annotations can be stacked on a single syntax element.
* <p>
* Each annotation should include a single example.
* This can be used instead of the existing {@link ch.njol.skript.doc.Examples} annotation.
* <p>
* <b>Multi-line examples</b> 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).
* <pre>{@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 ... {
* }
* }</pre>
*/
@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();

}

}
36 changes: 26 additions & 10 deletions src/main/java/ch/njol/skript/doc/HTMLGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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("<br>").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples.value()) : null), "Missing examples.")));
desc = desc.replace("${element.examples-safe}", Joiner.on("<br>").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));
Expand Down Expand Up @@ -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("<br>").join(getDefaultIfNullOrEmpty((examples != null ? Documentation.escapeHTML(examples) : null), "Missing examples.")));
desc = desc.replace("${element.examples-safe}", Joiner.on("<br>").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;
Expand Down
17 changes: 14 additions & 3 deletions src/main/java/ch/njol/skript/doc/JSONGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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());
}
Expand Down
Loading