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

Shortened Timespans (in commands) #6786

Closed
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ public String toVariableNameString(final Time o) {
@Nullable
public Timespan parse(final String s, final ParseContext context) {
try {
return Timespan.parse(s);
return Timespan.parse(s, context);
} catch (IllegalArgumentException e) {
Skript.error("'" + s + "' is not a valid timespan");
return null;
Expand Down
66 changes: 63 additions & 3 deletions src/main/java/ch/njol/skript/util/Timespan.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import java.util.regex.Pattern;
import java.util.Locale;

import ch.njol.skript.aliases.AliasesMap;
import ch.njol.skript.lang.ParseContext;
import org.eclipse.jdt.annotation.Nullable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.ApiStatus.ScheduledForRemoval;
Expand Down Expand Up @@ -94,18 +96,33 @@ public void onLanguageChange() {
private static final Pattern TIMESPAN_PATTERN = Pattern.compile("^(\\d+):(\\d\\d)(:\\d\\d){0,2}(?<ms>\\.\\d{1,4})?$");
private static final Pattern TIMESPAN_NUMBER_PATTERN = Pattern.compile("^\\d+(\\.\\d+)?$");
private static final Pattern TIMESPAN_SPLIT_PATTERN = Pattern.compile("[:.]");
private static final Pattern TIMESPAN_SHORTENED_PATTERN = Pattern.compile("(\\d+)([smhd])");

private final long millis;

@Nullable
public static Timespan parse(String value) {
if (value.isEmpty())
return parse(value, ParseContext.DEFAULT);
}

@Nullable
public static Timespan parse(String value, ParseContext context) {
if (value.isEmpty()) {
return null;
}

long t = 0;
boolean minecraftTime = false;
boolean isMinecraftTimeSet = false;

// Check if the context allows for shortened timespan parsing
if (context == ParseContext.COMMAND) {
Timespan shortenedTimespan = parseShortenedTimespan(value, context);
if (shortenedTimespan != null) {
return shortenedTimespan;
}
}

Matcher matcher = TIMESPAN_PATTERN.matcher(value);
if (matcher.matches()) { // MM:SS[.ms] or HH:MM:SS[.ms] or DD:HH:MM:SS[.ms]
String[] substring = TIMESPAN_SPLIT_PATTERN.split(value);
Expand Down Expand Up @@ -179,7 +196,50 @@ else if (length == 3 && !hasMs || length == 4) // HH:MM:SS[.ms]

return new Timespan(t);
}



/**
* Parses a shortened timespan (e.g., "5m", "3d", "1h") based on the provided input string and parse context.
* Returns null if the input does not represent a valid shortened timespan in the context of a command argument.
*
* @param input The input string representing the shortened timespan.
* @param context The parse context to determine if parsing is allowed.
* @return A Timespan object representing the parsed timespan, or null if parsing fails or not allowed in context.
*/
@Nullable
public static Timespan parseShortenedTimespan(String input, ParseContext context) {
if (context != ParseContext.COMMAND) {
return null;
}
Asleeepp marked this conversation as resolved.
Show resolved Hide resolved

long totalMillis = 0;
Matcher matcher = TIMESPAN_SHORTENED_PATTERN.matcher(input);

while (matcher.find()) {
int value = Integer.parseInt(matcher.group(1));
char unit = matcher.group(2).charAt(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern will pick up a match within a larger string (e.g. abc(1d)ef) which is good if you want to extract multiple matches (like 1d 2h) but will also pick up things it probably shouldn't (e.g. (10m)onths).
image
You can either limit this to just one match of the entire input (using the ^ and $ start and end tokens) or you can use some logic to make sure it's not the start of a larger text (e.g. (?!\\w)).

Copy link
Contributor Author

@Asleeepp Asleeepp Jun 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sovde told me to go a different route, and add shorter versions in the default.lang, and then let the parser handle it. Which i'll try to fix up and finish today, as i didnt have much time yesterday.


switch (unit) {
case 'd':
Comment on lines +218 to +223
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this handle 15doubles?

totalMillis += value * 86400000L; // 1 day in milliseconds
break;
case 'h':
totalMillis += value * 3600000L; // 1 hour in milliseconds
break;
case 'm':
totalMillis += value * 60000L; // 1 minute in milliseconds
break;
case 's':
totalMillis += value * 1000L; // 1 second in milliseconds
break;
default:
throw new IllegalArgumentException("Unknown time unit: " + unit);
}
}
return totalMillis > 0 ? new Timespan(totalMillis) : null;
}


public Timespan() {
millis = 0;
}
Expand Down