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

Add list transformation expression and effect #7028

Merged
merged 14 commits into from
Jan 1, 2025
40 changes: 26 additions & 14 deletions src/main/java/ch/njol/skript/classes/ClassInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ public class ClassInfo<T> implements Debuggable {
@Nullable
private Cloner<T> cloner = null;

@Nullable
private Pattern[] userInputPatterns = null;

private Pattern @Nullable [] userInputPatterns = null;

@Nullable
private Changer<? super T> changer = null;
Expand All @@ -81,16 +81,12 @@ public class ClassInfo<T> implements Debuggable {

@Nullable
private String docName = null;
@Nullable
private String[] description = null;
@Nullable
private String[] usage = null;
@Nullable
private String[] examples = null;
private String @Nullable [] description = null;
private String @Nullable [] usage = null;
private String @Nullable [] examples = null;
@Nullable
private String since = null;
@Nullable
private String[] requiredPlugins = null;
private String @Nullable [] requiredPlugins = null;

/**
* Overrides documentation id assigned from class name.
Expand Down Expand Up @@ -368,12 +364,28 @@ public Cloner<? extends T> getCloner() {
public T clone(T t) {
return cloner == null ? t : cloner.clone(t);
}

@Nullable
public Pattern[] getUserInputPatterns() {

public Pattern @Nullable [] getUserInputPatterns() {
return userInputPatterns;
}


/**
* Checks whether the given input matches any of the user input patterns.
*
* @param input The user input string to be checked against the patterns.
* @return true if the input matches any of the patterns, false otherwise.
*/
public boolean matchesUserInput(String input) {
if (userInputPatterns == null)
return false;
for (Pattern typePattern : userInputPatterns) {
if (typePattern.matcher(input).matches()) {
return true;
}
}
return false;
}

@Nullable
public Changer<? super T> getChanger() {
return changer;
Expand Down
49 changes: 11 additions & 38 deletions src/main/java/ch/njol/skript/effects/EffSort.java
sovdeeth marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
/**
* This file is part of Skript.
*
* Skript is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Skript is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Skript. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright Peter Güttinger, SkriptLang team and contributors
*/
package ch.njol.skript.effects;

import ch.njol.skript.Skript;
Expand All @@ -30,15 +12,14 @@
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.InputSource;
import ch.njol.skript.lang.ParseContext;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.Variable;
import ch.njol.skript.lang.parser.ParserInstance;
import ch.njol.util.Kleenean;
import ch.njol.util.Pair;
import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;

import java.util.HashSet;
Expand Down Expand Up @@ -69,19 +50,15 @@ public class EffSort extends Effect implements InputSource {
ParserInstance.registerData(InputData.class, InputData::new);
}

@Nullable
private Expression<?> mappingExpr;
@Nullable
private String unparsedExpression;
private Variable<?> unsortedObjects;

private @Nullable Expression<?> mappingExpr;
private @UnknownNullability Variable<?> unsortedObjects;
private boolean descendingOrder;

private Set<ExprInput<?>> dependentInputs = new HashSet<>();
private final Set<ExprInput<?>> dependentInputs = new HashSet<>();

@Nullable
private Object currentValue;
@UnknownNullability
private String currentIndex;
private @Nullable Object currentValue;
private @UnknownNullability String currentIndex;

@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
Expand All @@ -92,16 +69,12 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean is
unsortedObjects = (Variable<?>) expressions[0];
descendingOrder = parseResult.hasTag("descending");

//noinspection DuplicatedCode
if (!parseResult.regexes.isEmpty()) {
unparsedExpression = parseResult.regexes.get(0).group();
@Nullable String unparsedExpression = parseResult.regexes.get(0).group();
assert unparsedExpression != null;
InputData inputData = getParser().getData(InputData.class);
InputSource originalSource = inputData.getSource();
inputData.setSource(this);
mappingExpr = new SkriptParser(unparsedExpression, SkriptParser.PARSE_EXPRESSIONS, ParseContext.DEFAULT)
.parseExpression(Object.class);
inputData.setSource(originalSource);
return mappingExpr != null && mappingExpr.isSingle();
mappingExpr = parseExpression(unparsedExpression, getParser(), SkriptParser.PARSE_EXPRESSIONS);
return mappingExpr != null;
}
return true;
}
Expand Down
139 changes: 139 additions & 0 deletions src/main/java/ch/njol/skript/effects/EffTransform.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package ch.njol.skript.effects;

import ch.njol.skript.Skript;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
import ch.njol.skript.doc.Keywords;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.Since;
import ch.njol.skript.expressions.ExprInput;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.InputSource;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.Variable;
import ch.njol.skript.lang.parser.ParserInstance;
import ch.njol.skript.variables.Variables;
import ch.njol.util.Kleenean;
import ch.njol.util.Pair;
import ch.njol.util.StringUtils;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

@Name("Transform List")
@Description({
"Transforms (or 'maps') a list's values using a given expression. This is akin to looping over the list and setting " +
"each value to a modified version of itself.",
"If the given expression returns a single value, the indices of the list will not change. If the expression returns " +
"multiple values, then then indices will be reset as a single index cannot contain multiple values.",
"Only variable lists can be transformed with this effect. For other lists, see the transform expression."
})
sovdeeth marked this conversation as resolved.
Show resolved Hide resolved
@Examples({
"set {_a::*} to 1, 2, and 3",
"transform {_a::*} using input * 2",
"# {_a::*} is now 2, 4, and 6",
"",
"# get a list of the sizes of all clans without manually looping",
"set {_clan-sizes::*} to indices of {clans::*}",
"transform {_clan-sizes::*} using {clans::%input%::size}"
})
@Since("INSERT VERSION")
@Keywords("input")
public class EffTransform extends Effect implements InputSource {

static {
Skript.registerEffect(EffTransform.class, "(transform|map) %~objects% (using|with) <.+>");
if (!ParserInstance.isRegistered(InputData.class))
ParserInstance.registerData(InputData.class, InputData::new);
}

private @UnknownNullability Expression<?> mappingExpr;
private @UnknownNullability Variable<?> unmappedObjects;

private final Set<ExprInput<?>> dependentInputs = new HashSet<>();

private @Nullable Object currentValue;
private @UnknownNullability String currentIndex;

@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
if (expressions[0].isSingle() || !(expressions[0] instanceof Variable)) {
sovdeeth marked this conversation as resolved.
Show resolved Hide resolved
Skript.error("You can only transform list variables!");
return false;
}
unmappedObjects = (Variable<?>) expressions[0];

//noinspection DuplicatedCode
if (!parseResult.regexes.isEmpty()) {
@Nullable String unparsedExpression = parseResult.regexes.get(0).group();
assert unparsedExpression != null;
mappingExpr = parseExpression(unparsedExpression, getParser(), SkriptParser.ALL_FLAGS);
return mappingExpr != null;
}
return true;
}

@Override
protected void execute(Event event) {
Map<String, Object> mappedValues = new HashMap<>();
assert mappingExpr != null;
boolean isSingle = mappingExpr.isSingle();

String varName = unmappedObjects.getName().toString(event);
String varSubName = StringUtils.substring(varName, 0, -1);
boolean local = unmappedObjects.isLocal();

int i = 1;
for (Iterator<Pair<String, Object>> it = unmappedObjects.variablesIterator(event); it.hasNext(); ) {
Pair<String, Object> pair = it.next();
currentIndex = pair.getKey();
currentValue = pair.getValue();

if (isSingle) {
mappedValues.put(currentIndex, mappingExpr.getSingle(event));
} else {
for (Object value : mappingExpr.getArray(event)) {
mappedValues.put(String.valueOf(i++), value);
mappedValues.putIfAbsent(currentIndex, null); // clears only unused indices instead of having to delete entire var.
}
}
}

for (Map.Entry<String, Object> pair : mappedValues.entrySet())
Variables.setVariable(varSubName + pair.getKey(), pair.getValue(), event, local);
}

@Override
public Set<ExprInput<?>> getDependentInputs() {
return dependentInputs;
}

@Override
public @Nullable Object getCurrentValue() {
return currentValue;
}

@Override
public boolean hasIndices() {
return true;
}

@Override
public @UnknownNullability String getCurrentIndex() {
return currentIndex;
}

@Override
public String toString(@Nullable Event event, boolean debug) {
return "transform " + unmappedObjects.toString(event, debug) + "using " + mappingExpr.toString(event, debug);
sovdeeth marked this conversation as resolved.
Show resolved Hide resolved
}

}
Loading