Skip to content
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
41 changes: 41 additions & 0 deletions src/main/java/ch/njol/skript/doc/JSONGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.bukkit.event.block.BlockCanBuildEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.lang.experiment.Experiment;
import org.skriptlang.skript.lang.structure.Structure;
import org.skriptlang.skript.lang.structure.StructureInfo;

Expand Down Expand Up @@ -366,6 +367,44 @@ private static JsonArray generateFunctionArray(Iterator<JavaFunction<?>> functio
return syntaxArray;
}

/**
* Generates a JsonArray with all data for each {@link Experiment}.
*
* @return a JsonArray containing the documentation JsonObjects for each experiment
*/
private static JsonArray generateExperiments() {
JsonArray array = new JsonArray();

for (Experiment experiment : Skript.experiments().registered()) {
JsonObject object = new JsonObject();

object.addProperty("id", experiment.codeName());

if (experiment.displayName().isEmpty()) {
object.addProperty("name", (String) null);
} else {
object.addProperty("name", experiment.displayName());
}

if (experiment.description().isEmpty()) {
object.add("description", null);
} else {
JsonArray description = new JsonArray();
for (String part : experiment.description()) {
description.add(part);
}
object.add("description", description);
}

object.addProperty("pattern", experiment.pattern().toString());
object.addProperty("phase", experiment.phase().name().toLowerCase(Locale.ENGLISH));

array.add(object);
}

return array;
}

/**
* Cleans the provided patterns
*
Expand Down Expand Up @@ -416,6 +455,8 @@ public void generate() {

jsonDocs.add("functions", generateFunctionArray(Functions.getJavaFunctions().iterator()));

jsonDocs.add("experiments", generateExperiments());

saveDocs(outputDir.toPath().resolve("docs.json"), jsonDocs);
}

Expand Down
178 changes: 169 additions & 9 deletions src/main/java/ch/njol/skript/registrations/Feature.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,178 @@
import ch.njol.skript.SkriptAddon;
import ch.njol.skript.patterns.PatternCompiler;
import ch.njol.skript.patterns.SkriptPattern;
import com.google.common.base.Preconditions;
import org.jetbrains.annotations.NotNull;
import org.skriptlang.skript.lang.experiment.Experiment;
import org.skriptlang.skript.lang.experiment.ExperimentRegistry;
import org.skriptlang.skript.lang.experiment.LifeCycle;

import java.util.Collection;
import java.util.List;

/**
* Experimental feature toggles as provided by Skript itself.
*/
public enum Feature implements Experiment {
EXAMPLES("examples", LifeCycle.STABLE),
QUEUES("queues", LifeCycle.EXPERIMENTAL),
FOR_EACH_LOOPS("for loop", LifeCycle.EXPERIMENTAL, "for [each] loop[s]"),
SCRIPT_REFLECTION("reflection", LifeCycle.EXPERIMENTAL, "[script] reflection"),
CATCH_ERRORS("catch runtime errors", LifeCycle.EXPERIMENTAL, "error catching [section]"),
TYPE_HINTS("type hints", LifeCycle.EXPERIMENTAL, "[local variable] type hints"),
DAMAGE_SOURCE("damage source", LifeCycle.EXPERIMENTAL, "damage source[s]")
;

EXAMPLES("examples",
"Examples",
"""
A section used to provide examples inside code.

```
example:
kick the player due to "you are not allowed here!"
```
""",
LifeCycle.STABLE),
QUEUES("queues",
"Queues",
"""
A collection that removes elements whenever they are requested.

This is useful for processing tasks or keeping track of things that need to happen only once.

```
set {queue} to a new queue of "hello" and "world"

broadcast the first element of {queue}
# "hello" is now removed

broadcast the first element of {queue}
# "world" is now removed

# queue is empty
```

```
set {queue} to a new queue of all players

set {player 1} to a random element out of {queue}\s
set {player 2} to a random element out of {queue}
# players 1 and 2 are guaranteed to be distinct
```

Queues can be looped over like a regular list.
""",
LifeCycle.EXPERIMENTAL),
FOR_EACH_LOOPS("for loop",
"For Loops",
"""
A new kind of loop syntax that stores the loop index and value in variables for convenience.

This can be used to avoid confusion when nesting multiple loops inside each other.

```
for {_index}, {_value} in {my list::*}:
broadcast "%{_index}%: %{_value}%"
```

```
for each {_player} in all players:
send "Hello %{_player}%!" to {_player}
```

All existing loop features are also available in this section.
""",
LifeCycle.EXPERIMENTAL,
"for [each] loop[s]"),
SCRIPT_REFLECTION("reflection",
"Script Reflection",
"""
This feature includes:

- The ability to reference a script in code.
- Finding and running functions by name.
- Reading configuration files and values.
""",
LifeCycle.EXPERIMENTAL,
"[script] reflection"),
CATCH_ERRORS("catch runtime errors",
"Runtime Error Catching",
"""
A new catch runtime errors section allows you to catch and \
suppress runtime errors within it and access them later with \
the last caught runtime errors.

```
catch runtime errors:
...
set worldborder center of {_border} to {_my unsafe location}
...
if last caught runtime errors contains "Your location can't have a NaN value as one of its components":
set worldborder center of {_border} to location(0, 0, 0)
```
""",
LifeCycle.EXPERIMENTAL,
"error catching [section]"),
TYPE_HINTS("type hints",
"Type Hints",
"""
Local variable type hints enable Skript to understand \
what kind of values your local variables will hold at parse time. \
Consider the following example:

```
set {_a} to 5
set {_b} to "some string"
... do stuff ...
set {_c} to {_a} in lowercase # oops i used the wrong variable
```

Previously, the code above would parse without issue. \
However, Skript now understands that when it is used, \
{_a} could only be a number (and not a text). \
Thus, the code above would now error with a message about mismatched types.

Please note that this feature is currently only supported by simple local variables. \
A simple local variable is one whose name does not contain any expressions:

```
{_var} # can use type hints
{_var::%player's name%} # can't use type hints
```
""",
LifeCycle.EXPERIMENTAL,
"[local variable] type hints"),
DAMAGE_SOURCE("damage source",
"Damage Sources",
"""
Damage sources are a more advanced and detailed version of damage causes. \
Damage sources include information such as the type of damage, \
the location where the damage originated from, the entity that \
directly caused the damage, and more.

Below is an example of what damaging using custom damage sources looks like:

```
damage all players by 5 using a custom damage source:
set the damage type to magic
set the causing entity to {_player}
set the direct entity to {_arrow}
set the damage location to location(0, 0, 10)
```

For more details about the syntax, visit damage source on our documentation website.
""",
LifeCycle.EXPERIMENTAL,
"damage source[s]");

private final String displayName;
private final String codeName;
private final String description;
private final LifeCycle phase;
private final SkriptPattern compiledPattern;

Feature(String codeName, LifeCycle phase, String... patterns) {
Feature(@NotNull String codeName, @NotNull String displayName,
@NotNull String description, @NotNull LifeCycle phase,
String... patterns) {
Preconditions.checkNotNull(codeName, "codeName cannot be null");
Preconditions.checkNotNull(displayName, "displayName cannot be null");
Preconditions.checkNotNull(description, "description cannot be null");

this.displayName = displayName;
this.description = description.strip();
this.codeName = codeName;
this.phase = phase;
this.compiledPattern = switch (patterns.length) {
Expand All @@ -40,6 +190,16 @@ public static void registerAll(SkriptAddon addon, ExperimentRegistry manager) {
}
}

@Override
public @NotNull String displayName() {
return displayName;
}

@Override
public @NotNull Collection<String> description() {
return List.of(description);
}

@Override
public String codeName() {
return codeName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ public SkriptPattern pattern() {
}

static {
registerAll(Skript.getAddonInstance(), Skript.experiments());
if (!TestMode.GEN_DOCS) {
registerAll(Skript.getAddonInstance(), Skript.experiments());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import ch.njol.skript.patterns.SkriptPattern;
import ch.njol.skript.registrations.Feature;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
Expand Down Expand Up @@ -56,6 +59,20 @@ default boolean isKnown() {
*/
SkriptPattern pattern();

/**
* @return The display name for this experiment.
*/
default @NotNull String displayName() {
return codeName();
}

/**
* @return The description for this experiment.
*/
default @NotNull Collection<String> description() {
return List.of();
}

/**
* @return Whether the usage pattern of this experiment matches the input text
*/
Expand Down