Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6723148
Init commit
Efnilite Sep 14, 2025
4213806
add example
Efnilite Sep 15, 2025
aa11019
Move to new registration API
Efnilite Sep 15, 2025
d4c7b51
wait :(
Efnilite Sep 17, 2025
35655aa
Merge branch 'dev/feature' into feature/grouped-docs
Efnilite Sep 17, 2025
34bc926
Add location, fix merge
Efnilite Sep 17, 2025
5616181
Remove set from register
Efnilite Sep 17, 2025
6fe255e
Make CategoryImpl use classes instead of instances
Efnilite Sep 17, 2025
afd70a7
Add docs, bug fix
Efnilite Sep 17, 2025
1d926c8
Add multiple categories per module
Efnilite Sep 17, 2025
4b79f1f
Apply suggestion from @Absolutionism
Efnilite Sep 18, 2025
3369e17
Apply suggestion from @Absolutionism
Efnilite Sep 18, 2025
278377c
Apply suggestion from @Absolutionism
Efnilite Sep 18, 2025
2dd2203
Merge branch 'dev/feature' into feature/grouped-docs
Efnilite Sep 18, 2025
dce21d6
Merge remote-tracking branch 'origin/feature/grouped-docs' into featu…
Efnilite Sep 19, 2025
87caead
Update docs
Efnilite Sep 19, 2025
5b914e8
Update annotation
Efnilite Sep 19, 2025
5f7eded
Add subcategories
Efnilite Sep 19, 2025
9ab6833
update module registration code
Efnilite Sep 20, 2025
6254455
requested changes part 1
Efnilite Sep 20, 2025
310880f
requested changes part 2
Efnilite Sep 20, 2025
ec002bd
set isDefault in infoBuilder to false
Efnilite Sep 20, 2025
a211958
Merge branch 'dev/feature' into feature/grouped-docs
Efnilite Sep 20, 2025
35cf06b
move DamageSourceModule to implement Categorizable instead of AddonMo…
Efnilite Sep 21, 2025
efe7536
requested changes
Efnilite Sep 21, 2025
b33472e
Merge branch 'dev/feature' into feature/grouped-docs
Efnilite Sep 21, 2025
e43f09b
Merge remote-tracking branch 'origin/feature/grouped-docs' into featu…
Efnilite Sep 21, 2025
03a7f86
Update src/main/java/ch/njol/skript/doc/JSONGenerator.java
Efnilite Sep 21, 2025
7023f3a
minor changes to annotations
Efnilite Sep 28, 2025
9645e27
Merge branch 'dev/feature' into feature/grouped-docs
Efnilite Oct 26, 2025
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
71 changes: 71 additions & 0 deletions src/main/java/ch/njol/skript/doc/Category.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package ch.njol.skript.doc;

import com.google.common.base.Preconditions;
import org.jetbrains.annotations.NotNull;
import org.skriptlang.skript.addon.AddonModule;

import java.util.HashSet;
import java.util.Set;

/**
* Represents a category a documented element can belong to.
*/
public interface Category {

Category ENTITIES = new CategoryImpl("Entities", "entity", "entities", "animal", "panda", "allay",
"zombie", "goat", "horse", "pig", "fish", "villager", "bee");
Category BREEDING = new CategoryImpl("Breeding");
Category PLAYERS = new CategoryImpl("Players", "player", "operator");
Category DAMAGE_SOURCES = new CategoryImpl("Damage Sources", "damage source");
Category BLOCKS = new CategoryImpl("Blocks", "block");
Category STRINGS = new CategoryImpl("Strings", "string", "text");
Category COMMANDS = new CategoryImpl("Commands", "command");
Category ITEMS = new CategoryImpl("Items", "item", "enchantment", "lore", "tooltip", "banner");
Category WORLDS = new CategoryImpl("Worlds", "world");
Category SCRIPTS = new CategoryImpl("Scripts", "script");
Category DISPLAYS = new CategoryImpl("Displays", "display");
Category TIME = new CategoryImpl("Time", "time", "unix");
Category UUIDS = new CategoryImpl("UUIDs", "uuid");
Category DATES = new CategoryImpl("Dates", "date");
Category LOCATIONS = new CategoryImpl("Locations", "location");
Category MATH = new CategoryImpl("Math", "angle", "degree", "radian",
"arithmetic", "vector", "vectors", "nan", "round", "rounds", "root", "quaternion", "permutations",
"combinations", "numbers", "infinity", "exponential");

/**
* @return The display name of this category.
*/
@NotNull String name();

/**
* Adds a module to this category.
*
* @param module The module to add.
*/
void addModule(@NotNull Class<? extends AddonModule> module);

/**
* @return The modules that are represented by this category.
*/
Set<Class<? extends AddonModule>> modules();

/**
* Creates a new category.
*
* @param name The name.
* @return The new category.
*/
static Category of(@NotNull String name) {
Preconditions.checkNotNull(name, "name cannot be null");

return new CategoryImpl(name, new HashSet<>());
}

/**
* @return All registered categories.
*/
static Set<Category> values() {
return CategoryImpl.getInstances();
}

}
55 changes: 55 additions & 0 deletions src/main/java/ch/njol/skript/doc/CategoryImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ch.njol.skript.doc;

import com.google.common.base.Preconditions;
import org.jetbrains.annotations.NotNull;
import org.skriptlang.skript.addon.AddonModule;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

final class CategoryImpl implements Category {

private static final Set<Category> instances = new HashSet<>();
private final String name;
private final Set<String> keywords;
private final Set<Class<? extends AddonModule>> modules;

public static Set<Category> getInstances() {
return instances;
}

CategoryImpl(String name, String... keywords) {
this(name, new HashSet<>(Set.of(keywords)));
}

CategoryImpl(String name, Set<String> keywords) {
instances.add(this);
this.name = name;
this.keywords = keywords.stream().map(String::toLowerCase).collect(Collectors.toSet());
this.modules = new HashSet<>();
}

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

public @NotNull Set<String> keywords() {
return keywords;
}

@Override
public void addModule(@NotNull Class<? extends AddonModule> module) {
Preconditions.checkNotNull(module, "module cannot be null");

modules.add(module);
}

@Override
public Set<Class<? extends AddonModule>> modules() {
return Collections.unmodifiableSet(modules);
}

}
53 changes: 52 additions & 1 deletion src/main/java/ch/njol/skript/doc/JSONGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import org.skriptlang.skript.addon.SkriptAddon;
import org.skriptlang.skript.bukkit.registration.BukkitRegistryKeys;
import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos;
import org.skriptlang.skript.lang.structure.Structure;
import org.skriptlang.skript.registration.DefaultSyntaxInfos;
import org.skriptlang.skript.registration.SyntaxInfo;
import org.skriptlang.skript.registration.SyntaxOrigin;
import org.skriptlang.skript.registration.SyntaxOrigin.ElementOrigin;
import org.skriptlang.skript.registration.SyntaxRegistry;

import java.io.File;
Expand Down Expand Up @@ -159,6 +162,9 @@ private static JsonObject generatedAnnotatedElement(SyntaxInfo<?> syntaxInfo) {
Keywords keywords = syntaxClass.getAnnotation(Keywords.class);
syntaxJsonObject.add("keywords", keywords == null ? null : convertToJsonArray(keywords.value()));

syntaxJsonObject.addProperty("category", getCategory(syntaxInfo.origin(), name.value(),
description == null ? null : List.of(description.value()), syntaxInfo.patterns()));

if (syntaxInfo instanceof SyntaxInfo.Expression<?, ?> expression) {
syntaxJsonObject.add("returns", getExpressionReturnTypes(expression));
}
Expand Down Expand Up @@ -224,7 +230,7 @@ private static JsonObject generateEventElement(BukkitSyntaxInfos.Event<?> info)
syntaxJsonObject.add("requirements", convertToJsonArray(info.requiredPlugins().toArray(new String[0])));
syntaxJsonObject.add("examples", convertToJsonArray(info.examples().toArray(new String[0])));
syntaxJsonObject.add("eventValues", getEventValues(info));
syntaxJsonObject.add("keywords", convertToJsonArray(info.keywords().toArray(new String[0])));
syntaxJsonObject.addProperty("category", getCategory(info.origin(), info.name(), info.description(), info.patterns()));

return syntaxJsonObject;
}
Expand Down Expand Up @@ -370,6 +376,9 @@ private static JsonObject generateClassInfoElement(ClassInfo<?> classInfo) {
syntaxJsonObject.add("description", convertToJsonArray(classInfo.getDescription()));
syntaxJsonObject.add("requirements", convertToJsonArray(classInfo.getRequiredPlugins()));
syntaxJsonObject.add("examples", convertToJsonArray(classInfo.getExamples()));
syntaxJsonObject.addProperty("category", getCategory(null,
Objects.requireNonNullElse(classInfo.getDocName(), classInfo.getCodeName()),
List.of(classInfo.getDescription()), null));

return syntaxJsonObject;
}
Expand Down Expand Up @@ -408,6 +417,7 @@ private static JsonObject generateFunctionElement(JavaFunction<?> function) {

String functionSignature = function.getSignature().toString(false, false);
functionJsonObject.add("patterns", convertToJsonArray(functionSignature));
functionJsonObject.addProperty("category", getCategory(null, function.getName(), List.of(function.getDescription()), null));
return functionJsonObject;
}

Expand Down Expand Up @@ -459,6 +469,47 @@ private static JsonArray cleanPatterns(String... strings) {
return convertToJsonArray(strings);
}

private static @Nullable String getCategory(SyntaxOrigin origin, String name, Collection<String> description, Collection<String> patterns) {
if (origin instanceof ElementOrigin elementOrigin) {
for (Category category : Category.values()) {
if (category.modules().contains(elementOrigin.module())) {
return category.name();
}
}
}

if (patterns == null) patterns = List.of();
String first = getCategory(String.join("", patterns));
if (first != null) {
return first;
} else {
if (description == null) description = List.of();
return getCategory(name + String.join("", description) + String.join("", patterns));
}
}

private static @Nullable String getCategory(String patterns) {
Set<Category> options = new HashSet<>();

for (Category value : Category.values()) {
if (!(value instanceof CategoryImpl impl)) {
break;
}

for (String keyword : impl.keywords()) {
if (patterns.toLowerCase().contains(keyword)) {
options.add(value);
break;
}
}
}

if (options.isEmpty()) {
return null;
}
return options.stream().findAny().orElseThrow().name();
}

/**
* Gets the json object representing the addon.
*
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/org/skriptlang/skript/addon/AddonModule.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package org.skriptlang.skript.addon;

import ch.njol.skript.doc.Category;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.Skript;
import org.skriptlang.skript.registration.SyntaxInfo;
import org.skriptlang.skript.registration.SyntaxOrigin;
import org.skriptlang.skript.registration.SyntaxRegistry.Key;

import java.util.Set;

/**
* A module is a component of a {@link SkriptAddon} used for registering syntax and other {@link Skript} components.
Expand Down Expand Up @@ -44,4 +51,41 @@ default boolean canLoad(SkriptAddon addon) {
return true;
}

/**
* @return The category to which this module belongs, or null if this module belongs to no category.
*/
default @Nullable Category category() {
return null;
}

/**
* Registers syntax such that it belongs to the current module.
*
* @param addon The addon this module belongs to.
* @param registry The registry to add this syntax to.
* @param cls The syntax info.
* @param <I> The type of syntax.
*/
default <I extends SyntaxInfo<?>> void register(SkriptAddon addon, Key<I> registry, I cls) {
//noinspection unchecked
addon.syntaxRegistry().register(registry, (I) cls.toBuilder()
.origin(SyntaxOrigin.of(addon, this))
.build());
}

/**
* Registers syntax such that it belongs to the current module.
*
* @param addon The addon this module belongs to.
* @param registry The registry to add this syntax to.
* @param classes The syntax infos.
* @param <I> The type of syntax.
*/
@SuppressWarnings("unchecked")
default <I extends SyntaxInfo<?>> void register(SkriptAddon addon, Key<I> registry, I... classes) {
for (I cls : classes) {
register(addon, registry, cls);
}
}

}
6 changes: 6 additions & 0 deletions src/main/java/org/skriptlang/skript/addon/SkriptAddon.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.skriptlang.skript.addon;

import ch.njol.skript.doc.Category;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.skriptlang.skript.Skript;
Expand Down Expand Up @@ -97,6 +98,11 @@ default void loadModules(AddonModule... modules) {

for (AddonModule module : filtered) {
module.init(this);

Category category = module.category();
if (category != null) {
category.addModule(module.getClass());
}
}
for (AddonModule module : filtered) {
module.load(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ch.njol.skript.Skript;
import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.classes.registry.RegistryClassInfo;
import ch.njol.skript.doc.Category;
import ch.njol.skript.expressions.base.EventValueExpression;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.registrations.EventValues;
Expand All @@ -11,10 +12,11 @@
import org.bukkit.damage.DamageType;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.addon.AddonModule;
import org.skriptlang.skript.addon.SkriptAddon;

import java.io.IOException;
import org.skriptlang.skript.bukkit.damagesource.elements.*;
import org.skriptlang.skript.registration.SyntaxRegistry;

public class DamageSourceModule implements AddonModule {

Expand Down Expand Up @@ -54,11 +56,19 @@ public void init(SkriptAddon addon) {

@Override
public void load(SkriptAddon addon) {
try {
Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit.damagesource", "elements");
} catch (IOException e) {
throw new RuntimeException(e);
}
register(addon, SyntaxRegistry.CONDITION,
CondScalesWithDifficulty.info(), CondWasIndirect.info());

register(addon, SyntaxRegistry.EXPRESSION,
ExprCausingEntity.info(), ExprCreatedDamageSource.info(),
ExprDamageLocation.info(), ExprDamageType.info(),
ExprDirectEntity.info(), ExprFoodExhaustion.info(),
ExprSecDamageSource.info(), ExprSourceLocation.info());
}

@Override
public @Nullable Category category() {
return Category.DAMAGE_SOURCES;
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.skriptlang.skript.bukkit.damagesource.elements;

import ch.njol.skript.Skript;
import ch.njol.skript.conditions.base.PropertyCondition;
import ch.njol.skript.doc.*;
import ch.njol.skript.lang.Expression;
Expand All @@ -11,24 +10,26 @@
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.bukkit.damagesource.DamageSourceExperimentSyntax;
import org.skriptlang.skript.registration.SyntaxInfo;

@Name("Damage Source - Does Scale With Difficulty")
@Description("Whether the damage from a damage source scales with the difficulty of the server.")
@Example("""
on death:
if event-damage source scales damage with difficulty:
""")
on death:
if event-damage source scales damage with difficulty:
""")
@Since("2.12")
@RequiredPlugins("Minecraft 1.20.4+")
@SuppressWarnings("UnstableApiUsage")
public class CondScalesWithDifficulty extends PropertyCondition<DamageSource> implements DamageSourceExperimentSyntax {

static {
Skript.registerCondition(CondScalesWithDifficulty.class,
"%damagesources% ((does|do) scale|scales) damage with difficulty",
"%damagesources% (do not|don't|does not|doesn't) scale damage with difficulty",
"%damagesources%'[s] damage ((does|do) scale|scales) with difficulty",
"%damagesources%'[s] damage (do not|don't|does not|doesn't) scale with difficulty");
public static SyntaxInfo<CondScalesWithDifficulty> info() {
return SyntaxInfo.builder(CondScalesWithDifficulty.class)
.supplier(CondScalesWithDifficulty::new)
.addPatterns("%damagesources% ((does|do) scale|scales) damage with difficulty",
"%damagesources% (do not|don't|does not|doesn't) scale damage with difficulty",
"%damagesources%'[s] damage ((does|do) scale|scales) with difficulty",
"%damagesources%'[s] damage (do not|don't|does not|doesn't) scale with difficulty")
.build();
}

@Override
Expand Down
Loading