feat: Improve content display API

- Change ContentProvider to return a list instead of add to existing
- Add prefix for inline handler
- Change from CommandSender to BukkitCommandIssuer, prep for locale
This commit is contained in:
Ben Woo 2023-02-13 23:31:26 +08:00
parent 7978193d88
commit 1c89b6458f
12 changed files with 155 additions and 121 deletions

View File

@ -1,15 +1,15 @@
package com.onarandombox.MultiverseCore.display; package com.onarandombox.MultiverseCore.display;
import com.onarandombox.MultiverseCore.display.handlers.DefaultSendHandler;
import com.onarandombox.MultiverseCore.display.handlers.SendHandler;
import com.onarandombox.MultiverseCore.display.parsers.ContentParser;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import co.aikar.commands.BukkitCommandIssuer;
import com.onarandombox.MultiverseCore.display.handlers.DefaultSendHandler;
import com.onarandombox.MultiverseCore.display.handlers.SendHandler;
import com.onarandombox.MultiverseCore.display.parsers.ContentProvider;
import org.jetbrains.annotations.NotNull;
/** /**
* Helps to display contents such as list and maps in a nicely formatted fashion. * Helps to display contents such as list and maps in a nicely formatted fashion.
*/ */
@ -25,7 +25,7 @@ public class ContentDisplay {
return new ContentDisplay(); return new ContentDisplay();
} }
private final List<ContentParser> contentParsers = new ArrayList<>(); private final List<ContentProvider> contentParsers = new ArrayList<>();
private SendHandler sendHandler = DefaultSendHandler.getInstance(); private SendHandler sendHandler = DefaultSendHandler.getInstance();
public ContentDisplay() { public ContentDisplay() {
@ -38,7 +38,7 @@ public class ContentDisplay {
* @return Same {@link ContentDisplay} for method chaining. * @return Same {@link ContentDisplay} for method chaining.
*/ */
@NotNull @NotNull
public ContentDisplay addContentParser(@NotNull ContentParser parser) { public ContentDisplay addContent(@NotNull ContentProvider parser) {
contentParsers.add(parser); contentParsers.add(parser);
return this; return this;
} }
@ -58,12 +58,12 @@ public class ContentDisplay {
/** /**
* Format and display the message to command sender. * Format and display the message to command sender.
* *
* @param sender The target command sender to show the display to. * @param issuer The target command sender to show the display to.
*/ */
public void send(@NotNull CommandSender sender) { public void send(@NotNull BukkitCommandIssuer issuer) {
Objects.requireNonNull(sendHandler, "No send handler set for content display"); Objects.requireNonNull(sendHandler, "No send handler set for content display");
List<String> parsedContent = new ArrayList<>(); List<String> parsedContent = new ArrayList<>();
contentParsers.forEach(parser -> parser.parse(sender, parsedContent)); contentParsers.forEach(parser -> parsedContent.addAll(parser.parse(issuer)));
sendHandler.send(sender, parsedContent); sendHandler.send(issuer, parsedContent);
} }
} }

View File

@ -32,4 +32,9 @@ public class DefaultContentFilter implements ContentFilter {
public boolean needToFilter() { public boolean needToFilter() {
return false; return false;
} }
@Override
public String toString() {
return "N/A";
}
} }

View File

@ -1,14 +1,14 @@
package com.onarandombox.MultiverseCore.display.filters; package com.onarandombox.MultiverseCore.display.filters;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import com.dumptruckman.minecraft.util.Logging; import com.dumptruckman.minecraft.util.Logging;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/** /**
* Filter content and text based on regex matching. * Filter content and text based on regex matching.
*/ */
@ -34,7 +34,7 @@ public class RegexContentFilter implements ContentFilter {
return new RegexContentFilter(filterString.substring(2)); return new RegexContentFilter(filterString.substring(2));
} }
String cleanedFilter = REGEX_SPECIAL_CHARS.matcher(filterString.toLowerCase()).replaceAll("\\\\$0"); String cleanedFilter = REGEX_SPECIAL_CHARS.matcher(filterString.toLowerCase()).replaceAll("\\\\$0");
return new RegexContentFilter("(?i).*" + cleanedFilter + ".*"); return new RegexContentFilter(cleanedFilter);
} }
private final String regexString; private final String regexString;

View File

@ -1,14 +1,15 @@
package com.onarandombox.MultiverseCore.display.handlers; package com.onarandombox.MultiverseCore.display.handlers;
import java.util.List;
import java.util.stream.Collectors;
import co.aikar.commands.BukkitCommandIssuer;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.onarandombox.MultiverseCore.display.filters.ContentFilter; import com.onarandombox.MultiverseCore.display.filters.ContentFilter;
import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter; import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* Base implementation of {@link SendHandler} with some common parameters. * Base implementation of {@link SendHandler} with some common parameters.
@ -19,29 +20,30 @@ public abstract class BaseSendHandler<T extends BaseSendHandler<?>> implements S
protected String header = ""; protected String header = "";
protected ContentFilter filter = DefaultContentFilter.getInstance(); protected ContentFilter filter = DefaultContentFilter.getInstance();
protected String noContentMessage = String.format("%sThere is no content to display.", ChatColor.RED);
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public void send(@NotNull CommandSender sender, @NotNull List<String> content) { public void send(@NotNull BukkitCommandIssuer issuer, @NotNull List<String> content) {
sendHeader(sender); sendHeader(issuer);
List<String> filteredContent = filterContent(content); List<String> filteredContent = filterContent(content);
if (filteredContent.isEmpty()) { if (filteredContent.isEmpty() && !Strings.isNullOrEmpty(noContentMessage)) {
sender.sendMessage(String.format("%sThere is no content to display.", ChatColor.RED)); issuer.sendMessage(noContentMessage);
return; return;
} }
sendContent(sender, filteredContent); sendContent(issuer, filteredContent);
} }
/** /**
* Sends the header if header is present. * Sends the header if header is present.
* *
* @param sender The target which the header will be displayed to. * @param issuer The target which the header will be displayed to.
*/ */
protected void sendHeader(CommandSender sender) { protected void sendHeader(BukkitCommandIssuer issuer) {
if (!Strings.isNullOrEmpty(header)) { if (!Strings.isNullOrEmpty(header)) {
sender.sendMessage(header); issuer.sendMessage(header);
} }
} }
@ -61,10 +63,10 @@ public abstract class BaseSendHandler<T extends BaseSendHandler<?>> implements S
/** /**
* Display the contents. * Display the contents.
* *
* @param sender The target which the content will be displayed to. * @param issuer The target which the content will be displayed to.
* @param content The content to display. * @param content The content to display.
*/ */
protected abstract void sendContent(@NotNull CommandSender sender, @NotNull List<String> content); protected abstract void sendContent(@NotNull BukkitCommandIssuer issuer, @NotNull List<String> content);
/** /**
* Sets header to be displayed. * Sets header to be displayed.
@ -89,6 +91,17 @@ public abstract class BaseSendHandler<T extends BaseSendHandler<?>> implements S
return (T) this; return (T) this;
} }
/**
* Sets the message to be displayed when there is no content to display.
*
* @param message The message to display. Null to disable.
* @return Same {@link T} for method chaining.
*/
public T noContentMessage(@Nullable String message) {
this.noContentMessage = message;
return (T) this;
}
public String getHeader() { public String getHeader() {
return header; return header;
} }
@ -96,4 +109,8 @@ public abstract class BaseSendHandler<T extends BaseSendHandler<?>> implements S
public ContentFilter getFilter() { public ContentFilter getFilter() {
return filter; return filter;
} }
public String getNoContentMessage() {
return noContentMessage;
}
} }

View File

@ -1,10 +1,10 @@
package com.onarandombox.MultiverseCore.display.handlers; package com.onarandombox.MultiverseCore.display.handlers;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import co.aikar.commands.BukkitCommandIssuer;
import org.jetbrains.annotations.NotNull;
public class DefaultSendHandler implements SendHandler { public class DefaultSendHandler implements SendHandler {
private static DefaultSendHandler instance; private static DefaultSendHandler instance;
@ -23,7 +23,7 @@ public class DefaultSendHandler implements SendHandler {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public void send(@NotNull CommandSender sender, @NotNull List<String> content) { public void send(@NotNull BukkitCommandIssuer issuer, @NotNull List<String> content) {
sender.sendMessage(content.toArray(new String[0])); content.forEach(issuer::sendMessage);
} }
} }

View File

@ -1,11 +1,11 @@
package com.onarandombox.MultiverseCore.display.handlers; package com.onarandombox.MultiverseCore.display.handlers;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import co.aikar.commands.BukkitCommandIssuer;
import org.bukkit.ChatColor;
import org.jetbrains.annotations.NotNull;
/** /**
* Display the contents in a single line. * Display the contents in a single line.
*/ */
@ -21,6 +21,7 @@ public class InlineSendHandler extends BaseSendHandler<InlineSendHandler> {
} }
private String delimiter = ChatColor.WHITE + ", "; private String delimiter = ChatColor.WHITE + ", ";
private String prefix = null;
public InlineSendHandler() { public InlineSendHandler() {
} }
@ -29,11 +30,15 @@ public class InlineSendHandler extends BaseSendHandler<InlineSendHandler> {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public void sendContent(@NotNull CommandSender sender, @NotNull List<String> content) { public void sendContent(@NotNull BukkitCommandIssuer issuer, @NotNull List<String> content) {
if (filter.needToFilter()) { if (filter.needToFilter()) {
sender.sendMessage(String.format("%s[Filter '%s']", ChatColor.GRAY, filter)); issuer.sendMessage(String.format("%s[Filter '%s']", ChatColor.GRAY, filter));
} }
sender.sendMessage(String.join(delimiter, content)); String message = String.join(delimiter, content);
if (prefix != null) {
message = prefix + message;
}
issuer.sendMessage(message);
} }
/** /**
@ -47,7 +52,16 @@ public class InlineSendHandler extends BaseSendHandler<InlineSendHandler> {
return this; return this;
} }
public InlineSendHandler withPrefix(String prefix) {
this.prefix = prefix;
return this;
}
public String getDelimiter() { public String getDelimiter() {
return delimiter; return delimiter;
} }
public String getPrefix() {
return prefix;
}
} }

View File

@ -1,12 +1,12 @@
package com.onarandombox.MultiverseCore.display.handlers; package com.onarandombox.MultiverseCore.display.handlers;
import java.util.List;
import co.aikar.commands.BukkitCommandIssuer;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.ConsoleCommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List;
/** /**
* Display content as a list with optional pagination. * Display content as a list with optional pagination.
*/ */
@ -34,50 +34,44 @@ public class PagedSendHandler extends BaseSendHandler<PagedSendHandler> {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public void sendContent(@NotNull CommandSender sender, public void sendContent(@NotNull BukkitCommandIssuer issuer, @NotNull List<String> content) {
@NotNull List<String> content) { if (!paginate || (issuer instanceof ConsoleCommandSender && !paginateInConsole)) {
sendNormal(issuer, content);
if (!paginate || (sender instanceof ConsoleCommandSender && !paginateInConsole)) {
sendNormal(sender, content);
return; return;
} }
sendPaged(sender, content); sendPaged(issuer, content);
} }
/** /**
* Send content list without pagination. * Send content list without pagination.
* *
* @param sender The target which the content will be displayed to. * @param issuer The target which the content will be displayed to.
* @param content The content to display. * @param content The content to display.
*/ */
private void sendNormal(@NotNull CommandSender sender, private void sendNormal(@NotNull BukkitCommandIssuer issuer, @NotNull List<String> content) {
@NotNull List<String> content) {
if (filter.needToFilter()) { if (filter.needToFilter()) {
sender.sendMessage(String.format("%s[Filter '%s']", ChatColor.GRAY, filter)); issuer.sendMessage(String.format("%s[Filter '%s']", ChatColor.GRAY, filter));
} }
sender.sendMessage(content.toArray(new String[0])); content.forEach(issuer::sendMessage);
} }
/** /**
* Send content list with pagination. * Send content list with pagination.
* *
* @param sender The target which the content will be displayed to. * @param issuer The target which the content will be displayed to.
* @param content The content to display. * @param content The content to display.
*/ */
private void sendPaged(@NotNull CommandSender sender, private void sendPaged(@NotNull BukkitCommandIssuer issuer, @NotNull List<String> content) {
@NotNull List<String> content) {
int totalPages = (content.size() + linesPerPage - 1) / linesPerPage; // Basically just divide round up int totalPages = (content.size() + linesPerPage - 1) / linesPerPage; // Basically just divide round up
if (targetPage < 1 || targetPage > totalPages) { if (targetPage < 1 || targetPage > totalPages) {
sender.sendMessage(String.format("%sInvalid page number. Please enter a page number between 1 and %s", ChatColor.RED, totalPages)); issuer.sendMessage(String.format("%sInvalid page number. Please enter a page number between 1 and %s", ChatColor.RED, totalPages));
return; return;
} }
if (filter.needToFilter()) { if (filter.needToFilter()) {
sender.sendMessage(String.format("%s[Page %s of %s] [Filter '%s']", ChatColor.GRAY, targetPage, totalPages, filter)); issuer.sendMessage(String.format("%s[Page %s of %s] [Filter '%s']", ChatColor.GRAY, targetPage, totalPages, filter));
} else { } else {
sender.sendMessage(String.format("%s[Page %s of %s]", ChatColor.GRAY, targetPage, totalPages)); issuer.sendMessage(String.format("%s[Page %s of %s]", ChatColor.GRAY, targetPage, totalPages));
} }
int startIndex = (targetPage - 1) * linesPerPage; int startIndex = (targetPage - 1) * linesPerPage;
@ -89,7 +83,7 @@ public class PagedSendHandler extends BaseSendHandler<PagedSendHandler> {
pageContent.add(""); pageContent.add("");
} }
} }
sender.sendMessage(pageContent.toArray(new String[0])); pageContent.forEach(issuer::sendMessage);
} }
/** /**

View File

@ -1,10 +1,10 @@
package com.onarandombox.MultiverseCore.display.handlers; package com.onarandombox.MultiverseCore.display.handlers;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import co.aikar.commands.BukkitCommandIssuer;
import org.jetbrains.annotations.NotNull;
/** /**
* Handles the sending of all content to the command sender. * Handles the sending of all content to the command sender.
*/ */
@ -16,5 +16,5 @@ public interface SendHandler {
* @param sender The target which the content will be displayed to. * @param sender The target which the content will be displayed to.
* @param content The content to display. * @param content The content to display.
*/ */
void send(@NotNull CommandSender sender, @NotNull List<String> content); void send(@NotNull BukkitCommandIssuer issuer, @NotNull List<String> content);
} }

View File

@ -1,20 +0,0 @@
package com.onarandombox.MultiverseCore.display.parsers;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Parse objects into string or list of strings.
*/
@FunctionalInterface
public interface ContentParser {
/**
* Parse the object to string(s) and add it to the content.
*
* @param sender The target which the content will be displayed to.
* @param content The content to display.
*/
void parse(@NotNull CommandSender sender, @NotNull List<String> content);
}

View File

@ -0,0 +1,19 @@
package com.onarandombox.MultiverseCore.display.parsers;
import java.util.Collection;
import co.aikar.commands.BukkitCommandIssuer;
import org.jetbrains.annotations.NotNull;
/**
* Parse objects into string or list of strings.
*/
@FunctionalInterface
public interface ContentProvider {
/**
* Parse the object to string(s) and add it to the content.
*
* @param issuer The target which the content will be displayed to.
*/
Collection<String> parse(@NotNull BukkitCommandIssuer issuer);
}

View File

@ -1,33 +1,35 @@
package com.onarandombox.MultiverseCore.display.parsers; package com.onarandombox.MultiverseCore.display.parsers;
import org.bukkit.command.CommandSender; import java.util.Collection;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import co.aikar.commands.BukkitCommandIssuer;
import org.jetbrains.annotations.NotNull;
/** /**
* Simple parser for list object. * Simple parser for list object.
* *
* @param <T> List element type. * @param <T> List element type.
*/ */
public class ListContentParser<T> implements ContentParser { public class ListContentProvider<T> implements ContentProvider {
/** /**
* New list content parser for the given list. * New list content parser for the given list.
* *
* @param list The list object to parse. * @param list The list object to parse.
* @param <T> List element type. * @param <T> List element type.
* @return New {@link MapContentParser} instance. * @return New {@link MapContentProvider} instance.
*/ */
public static <T> ListContentParser<T> forContent(List<T> list) { public static <T> ListContentProvider<T> forContent(List<T> list) {
return new ListContentParser<>(list); return new ListContentProvider<>(list);
} }
private final List<T> list; private final List<T> list;
private String format = "%s"; private String format = "%s";
public ListContentParser(List<T> list) { public ListContentProvider(List<T> list) {
this.list = list; this.list = list;
} }
@ -35,17 +37,17 @@ public class ListContentParser<T> implements ContentParser {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public void parse(@NotNull CommandSender sender, @NotNull List<String> content) { public Collection<String> parse(@NotNull BukkitCommandIssuer issuer) {
list.forEach(element -> content.add(String.format(format, element))); return list.stream().map(element -> String.format(format, element)).collect(Collectors.toList());
} }
/** /**
* Sets the format that will be used to parse each list entry. Uses java string format pattern. * Sets the format that will be used to parse each list entry. Uses java string format pattern.
* *
* @param format The format to use. * @param format The format to use.
* @return Same {@link ListContentParser} for method chaining. * @return Same {@link ListContentProvider} for method chaining.
*/ */
public ListContentParser<T> withFormat(String format) { public ListContentProvider<T> withFormat(String format) {
this.format = format; this.format = format;
return this; return this;
} }

View File

@ -1,11 +1,12 @@
package com.onarandombox.MultiverseCore.display.parsers; package com.onarandombox.MultiverseCore.display.parsers;
import org.bukkit.ChatColor; import java.util.Collection;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import co.aikar.commands.BukkitCommandIssuer;
import org.bukkit.ChatColor;
import org.jetbrains.annotations.NotNull;
/** /**
* Simple parser for map object. * Simple parser for map object.
@ -13,7 +14,7 @@ import java.util.Map;
* @param <K> Key type. * @param <K> Key type.
* @param <V> Value type. * @param <V> Value type.
*/ */
public class MapContentParser<K, V> implements ContentParser { public class MapContentProvider<K, V> implements ContentProvider {
/** /**
* New map content parser for the given map. * New map content parser for the given map.
@ -21,10 +22,10 @@ public class MapContentParser<K, V> implements ContentParser {
* @param map The map object to parse. * @param map The map object to parse.
* @param <K> Key type. * @param <K> Key type.
* @param <V> Value type. * @param <V> Value type.
* @return New {@link MapContentParser} instance. * @return New {@link MapContentProvider} instance.
*/ */
public static <K, V> MapContentParser<K, V> forContent(Map<K, V> map) { public static <K, V> MapContentProvider<K, V> forContent(Map<K, V> map) {
return new MapContentParser<>(map); return new MapContentProvider<>(map);
} }
private final Map<K, V> map; private final Map<K, V> map;
@ -34,7 +35,7 @@ public class MapContentParser<K, V> implements ContentParser {
private ChatColor valueColor = ChatColor.WHITE; private ChatColor valueColor = ChatColor.WHITE;
private String separator = ": "; private String separator = ": ";
public MapContentParser(Map<K, V> map) { public MapContentProvider(Map<K, V> map) {
this.map = map; this.map = map;
} }
@ -42,17 +43,19 @@ public class MapContentParser<K, V> implements ContentParser {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public void parse(@NotNull CommandSender sender, @NotNull List<String> content) { public Collection<String> parse(@NotNull BukkitCommandIssuer issuer) {
map.forEach((k, v) -> content.add(String.format(format, keyColor, k, separator, valueColor, v))); return map.entrySet().stream()
.map(e -> String.format(format, keyColor, e.getKey(), separator, valueColor, e.getValue()))
.collect(Collectors.toList());
} }
/** /**
* Sets the format that will be used to parse each map entry. Uses java string format pattern. * Sets the format that will be used to parse each map entry. Uses java string format pattern.
* *
* @param format The format to use. * @param format The format to use.
* @return Same {@link MapContentParser} for method chaining. * @return Same {@link MapContentProvider} for method chaining.
*/ */
public MapContentParser<K, V> withFormat(String format) { public MapContentProvider<K, V> withFormat(String format) {
this.format = format; this.format = format;
return this; return this;
} }
@ -61,9 +64,9 @@ public class MapContentParser<K, V> implements ContentParser {
* Sets the color for the key text. * Sets the color for the key text.
* *
* @param keyColor The color to use. * @param keyColor The color to use.
* @return Same {@link MapContentParser} for method chaining. * @return Same {@link MapContentProvider} for method chaining.
*/ */
public MapContentParser<K, V> withKeyColor(ChatColor keyColor) { public MapContentProvider<K, V> withKeyColor(ChatColor keyColor) {
this.keyColor = keyColor; this.keyColor = keyColor;
return this; return this;
} }
@ -72,9 +75,9 @@ public class MapContentParser<K, V> implements ContentParser {
* Sets the color for the value text. * Sets the color for the value text.
* *
* @param valueColor The color to use. * @param valueColor The color to use.
* @return Same {@link MapContentParser} for method chaining. * @return Same {@link MapContentProvider} for method chaining.
*/ */
public MapContentParser<K, V> withValueColor(ChatColor valueColor) { public MapContentProvider<K, V> withValueColor(ChatColor valueColor) {
this.valueColor = valueColor; this.valueColor = valueColor;
return this; return this;
} }
@ -83,9 +86,9 @@ public class MapContentParser<K, V> implements ContentParser {
* Sets the separator between each key value pairing. * Sets the separator between each key value pairing.
* *
* @param separator The separator to use. * @param separator The separator to use.
* @return Same {@link MapContentParser} for method chaining. * @return Same {@link MapContentProvider} for method chaining.
*/ */
public MapContentParser<K, V> withSeparator(String separator) { public MapContentProvider<K, V> withSeparator(String separator) {
this.separator = separator; this.separator = separator;
return this; return this;
} }