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 Indices of X in List #7323

Open
wants to merge 29 commits into
base: dev/feature
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
84c9279
fix test
Burbulinis Dec 29, 2024
5506397
Merge branch 'dev/feature' into feature/indicesofx
Burbulinis Dec 29, 2024
8c60253
change test
Burbulinis Dec 29, 2024
d1a6642
Clean up the example
Burbulinis Dec 29, 2024
b48c447
Changes
Burbulinis Dec 29, 2024
970a809
Tidy up error message
Burbulinis Dec 29, 2024
7e16be8
Fix bug
Burbulinis Dec 29, 2024
09de482
Tiny error
Burbulinis Dec 29, 2024
5928603
Fix null return values
Burbulinis Dec 29, 2024
b2a5735
Allow non-variable lists and add position syntax
Burbulinis Dec 29, 2024
98ba05c
Fix indentation in test
Burbulinis Dec 29, 2024
7dc918f
Changes
Burbulinis Dec 29, 2024
e6ee8cc
Fix bug
Burbulinis Dec 29, 2024
234c8c4
ok.
Burbulinis Dec 29, 2024
dcb21ba
Clean up the class
Burbulinis Dec 30, 2024
ad15364
Changes
Burbulinis Dec 30, 2024
edb0024
Merge branch 'dev/feature' into feature/indicesofx
Moderocky Dec 30, 2024
8f8abea
Return Integer or String when value is null
Burbulinis Dec 30, 2024
6926715
Merge remote-tracking branch 'fork/feature/indicesofx' into feature/i…
Burbulinis Dec 30, 2024
66713d0
fix
Burbulinis Dec 30, 2024
c137e3d
Changes
Burbulinis Dec 31, 2024
968c108
Merge ExprIndicesOfX with ExprIndicesOf (renamed the class for clarity)
Burbulinis Dec 31, 2024
4d962b9
Clean up
Burbulinis Dec 31, 2024
690f55c
Fix pattern
Burbulinis Dec 31, 2024
e9c5ceb
Merge branch 'dev/feature' into feature/indicesofx
Efnilite Jan 1, 2025
062fc0b
Fix example
Burbulinis Jan 1, 2025
6680cd2
Merge remote-tracking branch 'fork/feature/indicesofx' into feature/i…
Burbulinis Jan 1, 2025
af134f9
Changes
Burbulinis Jan 1, 2025
3182e9b
Clear up the description
Burbulinis Jan 2, 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: 0 additions & 71 deletions src/main/java/ch/njol/skript/expressions/ExprIndexOf.java

This file was deleted.

214 changes: 214 additions & 0 deletions src/main/java/ch/njol/skript/expressions/ExprIndicesOf.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package ch.njol.skript.expressions;

import ch.njol.skript.lang.SyntaxStringBuilder;
import ch.njol.skript.lang.Variable;
import ch.njol.skript.util.LiteralUtils;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.ExpressionType;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.util.SimpleExpression;
import ch.njol.util.Kleenean;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
* @author Peter Güttinger
*/
@Name("Index Of")
@Description({
"The first, last or all indices of a character (or text) in a text, or -1 if it doesn't occur in the text."
+ "Indices range from 1 to the <a href='#ExprIndicesOf'>length</a> of the text.",
"You can also get the indices or positions of a list where the value at that index is the provided value. "
+ "Indices are only supported for variable lists and will return the string indices of the given value. "
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
+ "Positions can be used with any list and will return the numerical position of the value in the list, counting up from 1."
})
@Examples({
"set {_first} to the first index of \"@\" in the text argument",
"if {_s} contains \"abc\":",
"\tset {_s} to the first (index of \"abc\" in {_s} + 3) characters of {_s} # removes everything after the first \"abc\" from {_s}",
"",
"set {_list::*} to 1, 2, 3, 1, 2, 3",
"set {_indices::*} to all indices of the value 1 in {_list::*}",
"# {_indices::*} is now \"1\" and \"4\"",
"",
"set {_indices::*} to all indices of the value 2 in {_list::*}",
"# {_indices::*} is now \"2\" and \"5\"",
"",
"set {_positions::*} to all positions of the value 3 in {_list::*}",
"# {_positions::*} is now 3 and 6",
"",
"set {_otherlist::bar} to 100",
"set {_otherlist::hello} to \"hi\"",
"set {_otherlist::burb} to 100",
"set {_otherlist::tud} to \"hi\"",
"set {_otherlist::foo} to 100",
"",
"set {_indices::*} to the first index of the value 100 in {_otherlist::*}",
"# {_indices::*} is now \"bar\"",
"set {_indices::*} to the last index of the value 100 in {_otherlist::*}",
"# {_indices::*} is now \"foo\"",
"",
"set {_positions::*} to all positions of the value 100 in {_otherlist::*}",
"# {_positions::*} is now 1, 3 and 5",
"set {_positions::*} to all positions of the value \"hi\" in {_otherlist::*}",
"# {_positions::*} is now 2 and 4"
})
@Since("2.1, INSERT VERSION (indices, positions of list)")
public class ExprIndicesOf extends SimpleExpression<Object> {

static {
Skript.registerExpression(ExprIndicesOf.class, Object.class, ExpressionType.COMBINED,
"[the] [first|1:last|2:all] (indices|index[es]) of [[the] value] %object% in %~objects%",
"[the] [first|1:last|2:all] position[s] of [[the] value] %object% in %~objects%",
"[the] [first|1:last|2:all] (position[s]|indices|index[es]) of [[the] value] %string% in %string%"
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
);
}

private IndexType type;
private boolean position;
private boolean string;
private Expression<?> value, objects;

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
if (exprs[1].isSingle() && (matchedPattern == 0 || matchedPattern == 1)) {
Skript.error("'" + exprs[1] + "' can only ever have one value at most, thus the 'indices of x in list' expression has no effect.");
return false;
}

if (!(exprs[1] instanceof Variable<?>) && matchedPattern == 0) {
Skript.error("'" + exprs[1] + "' is not a list variable. You can only get the indices of a list variable.");
return false;
}

type = IndexType.values()[parseResult.mark];
position = matchedPattern == 1 || matchedPattern == 2;
string = matchedPattern == 2;
value = LiteralUtils.defendExpression(exprs[0]);
objects = exprs[1];

return LiteralUtils.canInitSafely(value);
}

@Override
protected Object @Nullable [] get(Event event) {
Object value = this.value.getSingle(event);
if (value == null)
return (Object[]) Array.newInstance(getReturnType(), 0);

if (this.position) {
List<Long> positions = new ArrayList<>();

if (string) {
String needle = (String) value;
String haystack = (String) objects.getSingle(event);
if (haystack == null)
return new Long[0];

long position = haystack.indexOf(needle);

if (type == IndexType.ALL) {
while (position != -1) {
positions.add(position + 1);
position = haystack.indexOf(needle, (int) position + 1);
}
return positions.toArray();
}

if (type == IndexType.LAST) {
position = haystack.lastIndexOf(needle);
}

return new Long[]{(position == -1 ? -1 : position + 1)};
}

long position = 1;
for (Object object : objects.getArray(event)) {
if (object.equals(value)) {
if (type == IndexType.FIRST)
return new Long[]{position};
positions.add(position);
}
position++;
}

if (type == IndexType.LAST)
return new Long[]{positions.get(positions.size() - 1)};
return positions.toArray();
}

assert objects instanceof Variable<?>;

Variable<?> list = (Variable<?>) objects;
//noinspection unchecked
Map<String, Object> variable = (Map<String, Object>) list.getRaw(event);
if (variable == null)
return new String[0];

List<String> indices = new ArrayList<>();

for (Entry<String, Object> entry : variable.entrySet()) {
Object entryValue = entry.getValue();
// the value of {foo::1} when {foo::1::bar} is set is a map with a null key of the value {foo::1}
if (entryValue instanceof Map<?, ?> map)
entryValue = map.get(null);

if (entryValue.equals(value)) {
if (type == IndexType.FIRST)
return new String[]{entry.getKey()};
indices.add(entry.getKey());
}
}

if (indices.isEmpty())
return new String[0];

if (type == IndexType.LAST)
return new String[]{indices.get(indices.size() - 1)};
return indices.toArray();
}

@Override
public boolean isSingle() {
return type == IndexType.FIRST || type == IndexType.LAST;
}

@Override
public Class<?> getReturnType() {
if (position)
return Long.class;
return String.class;
}

@Override
public String toString(@Nullable Event event, boolean debug) {
SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug);

builder.append(type.name().toLowerCase());
if (position) {
builder.append("positions");
} else {
builder.append("index");
}
builder.append("of value", value, "in", objects);

return builder.toString();
}

private enum IndexType {
FIRST, LAST, ALL
}

}
28 changes: 28 additions & 0 deletions src/test/skript/tests/syntaxes/expressions/ExprIndicesOfX.sk
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
test "index of":
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
set {_list::*} to 1, 2, 3, 1, 2 and 3
set {_indices::*} to all indices of the value 1 in {_list::*}
assert {_indices::*} is "1" and "4" with "indices of 1 failed"

set {_indices::*} to the first index of the value 3 in {_list::*}
assert {_indices::*} is "3" with "first index of 3 failed"

set {_indices::*} to the last index of the value 3 in {_list::*}
assert {_indices::*} is "6" with "last index of 3 failed"

set {_indices::*} to the first position of the value 3 in {_list::*}
assert {_indices::*} is 3 with "first index of 3 failed"

set {_indices::*} to the last position of the value 3 in {_list::*}
assert {_indices::*} is 6 with "last index of 3 failed"

set {_otherlist::burb} to test-location
set {_otherlist::_DJ8U3f;} to test-location
set {_otherlist::;'w20} to test-location
set {_otherList::breh} to 2
set {_otherList::quatro} to 4

set {_indices::*} to all indices of the value test-location in {_otherlist::*}
assert {_indices::*} is ";'w20", "_dj8u3f;" and "burb" with "indices of test-location with symbols failed"

set {_indices::*} to all positions of the value test-location in {_otherList::*}
assert {_indices::*} is 1, 2 and 4 with "positions of test-location failed"
Loading