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 15 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
184 changes: 184 additions & 0 deletions src/main/java/ch/njol/skript/expressions/ExprIndicesOfX.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package ch.njol.skript.expressions;

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.*;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.util.SimpleExpression;
import ch.njol.skript.util.LiteralUtils;
import ch.njol.util.Kleenean;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Name("Indices of X in List")
@Description(
"Returns 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. " +
"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 {_list::*} to 1, 2, 3, 1, 2, 3",
"set {_indices::*} to the indices of the value 1 in {_list::*}",
"# {_indices::*} is now \"1\" and \"4\"",
"",
"set {_indices::*} to the indices of the value 2 in {_list::*}",
"# {_indices::*} is now \"2\" and \"5\"",
"",
"set {_positions::*} to the 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 the positions of the value 100 in {_otherlist::*}",
"# {_positions::*} is now 1, 3 and 5",
"set {_positions::*} to the positions of the value \"hi\" in {_otherlist::*}",
"# {_positions::*} is now 2 and 4",
"",
"set {_positions::*} to positions of \"mega\" in \"small\", \"mega\", \"mega\", \"medium\", \"small\" and \"mega\"",
"# {_positions::*} is now 2, 3 and 6"
})
@Since("INSERT VERSION")
public class ExprIndicesOfX extends SimpleExpression<Object> {

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

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

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
if (exprs[1].isSingle()) {
Skript.error("'" + exprs[1].toString(null, false) +
"' can only ever have one value at most, thus the 'indices of x in list' expression has no effect.");
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

if (!(exprs[1] instanceof Variable<?>) && matchedPattern == 0) {
Skript.error("'" + exprs[1].toString(null, false) +
"' is not a list variable. You can only get the indices of a list variable.");
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

position = matchedPattern == 1;
objects = LiteralUtils.defendExpression(exprs[1]);
type = IndexType.values()[parseResult.mark];
value = LiteralUtils.defendExpression(exprs[0]);
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved

return LiteralUtils.canInitSafely(objects, value);
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
protected Object @Nullable [] get(Event event) {
Object value = this.value.getSingle(event);
if (value == null)
return new String[0];

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

int position = 1;
if (objects instanceof Variable<?> list) {
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
//noinspection unchecked
Map<String, Object> variable = (Map<String, Object>) list.getRaw(event);
if (variable == null)
return new String[0];

for (Map.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)) {
Object index = getPositionOrIndex(entry.getKey(), position, this.position);

if (type == IndexType.FIRST)
return new Object[]{index};
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved

indices.add(index);
}
position++;
}
} else {
for (Object object : objects.getArray(event)) {
if (object.equals(value)) {
if (type == IndexType.FIRST)
return new Object[]{position};
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved

indices.add(position);
}
position++;
}
}

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

if (type == IndexType.LAST)
return new Object[]{indices.get(indices.size() - 1)};
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved

return indices.toArray();
}

private Object getPositionOrIndex(String key, int position, boolean count) {
if (count)
return position;
return key;
}
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved

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

@Override
public Class<?> getReturnType() {
if (!(objects instanceof Variable<?>) || position)
return Integer.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 (type == IndexType.ALL) {
builder.append("indices");
} else if (position) {
builder.append("positions");
Burbulinis marked this conversation as resolved.
Show resolved Hide resolved
} else {
builder.append("index");
}
builder.append("of value", value, "in", objects);

return builder.toString();
}

private enum IndexType {
ALL, FIRST, LAST
}

}
31 changes: 31 additions & 0 deletions src/test/skript/tests/syntaxes/expressions/ExprIndicesOfX.sk
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
test "indices of x":
set {_list::*} to 1, 2, 3, 1, 2 and 3
set {_indices::*} to the 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 the 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 the positions of the value test-location in {_otherList::*}
assert {_indices::*} is 1, 2 and 4 with "positions of test-location failed"

set {_indices::*} to the positions of the value 2 in 1, 2, 2, 4 and 2
assert {_indices::*} is 2, 3 and 5 with "indices of 2 failed"
Loading