Compare commits

...
4 Commits
Author SHA1 Message Date
d72bb9a1b4 Add Space Mode Settings to Search (#571)
Co-authored-by: slprime <[email protected]>
Co-authored-by: boubou19 <[email protected]>
2024-12-23 11:24:33 +01:00
Martin Robertz 23ea7e7d04 update
(cherry picked from commit 7ac3e32635)
2024-12-17 20:37:22 +01:00
Martin Robertz 6a8da78476 update
(cherry picked from commit 088d37a11a)
2024-12-17 20:37:15 +01:00
slprime 36c80863c6 Clear Search Filter Cache after Change Settings (#569)
(cherry picked from commit 6a787dd5b7)
2024-12-17 20:37:09 +01:00
11 changed files with 238 additions and 129 deletions

No files matched your search

Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
+1 -1
View File
@@ -17,7 +17,7 @@ pluginManagement {
}
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.29'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.30'
}
@@ -432,7 +432,15 @@ public class NEIClientConfig {
API.addOption(new OptionCycled("inventory.search.widgetAutofocus", 3, true));
tag.getTag("inventory.search.patternMode").setComment("Search Mode").getIntValue(1);
API.addOption(new OptionCycled("inventory.search.patternMode", 3, true));
API.addOption(new OptionCycled("inventory.search.patternMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
});
tag.getTag("inventory.search.quoteDropItemName").setComment("Quote Drop Item Name").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.search.quoteDropItemName", true));
@@ -449,6 +457,7 @@ public class NEIClientConfig {
}
if (state()) {
NEIClientConfig.setIntSetting("inventory.search.spaceMode", 1);
NEIClientConfig.setIntSetting("inventory.search.modNameSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.tooltipSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.identifierSearchMode", 0);
@@ -458,7 +467,9 @@ public class NEIClientConfig {
SearchField.searchParser.prefixRedefinitions.clear();
SearchField.searchParser.prefixRedefinitions.put('%', '@');
SearchField.searchParser.prefixRedefinitions.put('@', '%');
SearchField.searchParser.clearCache();
} else {
NEIClientConfig.setIntSetting("inventory.search.spaceMode", 0);
NEIClientConfig.setIntSetting("inventory.search.modNameSearchMode", 1);
NEIClientConfig.setIntSetting("inventory.search.tooltipSearchMode", 0);
NEIClientConfig.setIntSetting("inventory.search.identifierSearchMode", 0);
@@ -466,6 +477,7 @@ public class NEIClientConfig {
NEIClientConfig.setIntSetting("inventory.search.subsetsSearchMode", 1);
tag.getTag("inventory.search.prefixRedefinitions").setValue("{}");
SearchField.searchParser.prefixRedefinitions.clear();
SearchField.searchParser.clearCache();
}
return true;
@@ -473,10 +485,32 @@ public class NEIClientConfig {
});
tag.getTag("inventory.search.spaceMode").setComment("Search Space Rules").getIntValue(0);
API.addOption(new OptionCycled("inventory.search.spaceMode", 3, true) {
@Override
public boolean onClick(int button) {
// SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public boolean isEnabled() {
return !tag.getTag("inventory.search.format").getBooleanValue();
}
});
tag.getTag("inventory.search.modNameSearchMode").setComment("Search mode for Mod Names (prefix: @)")
.getIntValue(1);
API.addOption(new OptionCycled("inventory.search.modNameSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
@@ -496,6 +530,12 @@ public class NEIClientConfig {
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.tooltipSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
@@ -514,6 +554,12 @@ public class NEIClientConfig {
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.identifierSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
@@ -532,6 +578,12 @@ public class NEIClientConfig {
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.oreDictSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
@@ -550,6 +602,12 @@ public class NEIClientConfig {
.getIntValue(1);
API.addOption(new OptionCycled("inventory.search.subsetsSearchMode", 3, true) {
@Override
public boolean onClick(int button) {
SearchField.searchParser.clearCache();
return super.onClick(button);
}
@Override
public String getButtonText() {
return translateN(
@@ -1,12 +1,12 @@
package codechicken.nei;
import java.util.List;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.FormattedTextField.TextFormatter;
import codechicken.nei.SearchTokenParser.SearchToken;
public class SearchTextFormatter implements TextFormatter {
@@ -17,63 +17,50 @@ public class SearchTextFormatter implements TextFormatter {
}
public String format(String text) {
final String[] parts = text.split("\\|");
final Pattern splitPattern = searchParser.getSplitPattern();
final String[] parts = (text + "| ").split("\\|");
StringJoiner formattedText = new StringJoiner(EnumChatFormatting.GRAY + "|");
for (String filterText : parts) {
Matcher filterMatcher = splitPattern.matcher(filterText);
for (int i = 0; i < parts.length - 1; i++) {
final String filterText = parts[i];
final List<SearchToken> tokens = searchParser.splitSearchText(filterText);
StringBuilder formattedPart = new StringBuilder();
int startIndex = 0;
while (filterMatcher.find()) {
boolean ignore = "-".equals(filterMatcher.group(2));
String firstChar = filterMatcher.group(3);
String token = filterMatcher.group(4);
boolean quotes = token.length() > 1 && token.startsWith("\"") && token.endsWith("\"");
if (quotes) {
token = token.substring(1, token.length() - 1);
}
formattedPart.append(filterText.substring(startIndex, filterMatcher.start()));
for (SearchToken token : tokens) {
formattedPart.append(filterText.substring(startIndex, token.start));
EnumChatFormatting tokenColor = EnumChatFormatting.RESET;
if (!firstChar.isEmpty()) {
tokenColor = searchParser.getProvider(firstChar.charAt(0)).getHighlightedColor();
if (token.firstChar != null) {
tokenColor = searchParser.getProvider(token.firstChar).getHighlightedColor();
}
if (ignore) {
if (token.ignore) {
formattedPart.append(EnumChatFormatting.BLUE + "-");
}
if (!firstChar.isEmpty()) {
formattedPart.append(tokenColor + firstChar);
if (token.firstChar != null) {
formattedPart.append(tokenColor + String.valueOf(token.firstChar));
}
if (quotes) {
if (token.quotes) {
formattedPart.append(EnumChatFormatting.GOLD + "\"");
}
if (!token.isEmpty()) {
formattedPart.append(tokenColor + token);
if (!token.rawText.isEmpty()) {
formattedPart.append(tokenColor + token.rawText);
}
if (quotes) {
if (token.quotes) {
formattedPart.append(EnumChatFormatting.GOLD + "\"");
}
startIndex = filterMatcher.end();
startIndex = token.end;
}
formattedPart.append(filterText.substring(startIndex, filterText.length()));
formattedText.add(formattedPart);
}
if (text.endsWith("|")) {
formattedText.add("");
}
return formattedText.toString();
}
}
@@ -2,11 +2,11 @@ package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -22,8 +22,6 @@ import codechicken.nei.ItemList.EverythingItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemList.NothingItemFilter;
import codechicken.nei.api.ItemFilter;
import gnu.trove.map.TCharCharMap;
import gnu.trove.map.hash.TCharCharHashMap;
public class SearchTokenParser {
@@ -42,6 +40,20 @@ public class SearchTokenParser {
}
}
public static class SearchToken {
public boolean ignore = false;
public boolean quotes = false;
public Character firstChar = null;
public String[] words;
public String rawText = "";
public int start = 0;
public int end = 0;
}
public static interface ISearchParserProvider {
public ItemFilter getFilter(String searchText);
@@ -88,38 +100,7 @@ public class SearchTokenParser {
}
}
private static class ItemFilterCache implements ItemFilter {
public ItemFilter filter;
private final ItemStackMap<Boolean> states = new ItemStackMap<>();
private final ReentrantLock lock = new ReentrantLock();
public ItemFilterCache(ItemFilter filter) {
this.filter = filter;
}
@Override
public boolean matches(ItemStack item) {
lock.lock();
try {
Boolean match = states.get(item);
if (match == null) {
states.put(item, match = this.filter.matches(item));
}
return match;
} catch (Throwable th) {
th.printStackTrace();
return false;
} finally {
lock.unlock();
}
}
}
private static final LinkedHashMap<String, ItemFilter> filtersCache = new LinkedHashMap<>() {
private final LinkedHashMap<String, ItemFilter> filtersCache = new LinkedHashMap<>() {
private static final long serialVersionUID = 1042213947848622164L;
@@ -131,7 +112,7 @@ public class SearchTokenParser {
protected final List<ISearchParserProvider> searchProviders;
protected final ProvidersCache providersCache = new ProvidersCache();
protected final TCharCharMap prefixRedefinitions = new TCharCharHashMap();
protected final Map<Character, Character> prefixRedefinitions = new HashMap<>();
public SearchTokenParser(List<ISearchParserProvider> searchProviders) {
this.searchProviders = searchProviders;
@@ -144,6 +125,11 @@ public class SearchTokenParser {
public void addProvider(ISearchParserProvider provider) {
this.searchProviders.add(provider);
this.providersCache.clear();
this.filtersCache.clear();
}
public void clearCache() {
this.filtersCache.clear();
}
protected List<ISearchParserProvider> getProviders() {
@@ -176,30 +162,84 @@ public class SearchTokenParser {
.findFirst().orElse(null);
}
public ItemFilter getFilter(String filterText) {
public synchronized ItemFilter getFilter(String filterText) {
filterText = EnumChatFormatting.getTextWithoutFormattingCodes(filterText).toLowerCase();
if (!filtersCache.containsKey(filterText)) {
final String[] parts = EnumChatFormatting.getTextWithoutFormattingCodes(filterText).toLowerCase()
.split("\\|");
return this.filtersCache.computeIfAbsent(filterText, text -> {
final String[] parts = text.split("\\|");
final List<ItemFilter> searchTokens = Arrays.stream(parts).map(this::parseSearchText).filter(s -> s != null)
.collect(Collectors.toCollection(ArrayList::new));
if (searchTokens.isEmpty()) {
filtersCache.put(filterText, new EverythingItemFilter());
return new EverythingItemFilter();
} else if (searchTokens.size() == 1) {
filtersCache.put(filterText, new IsRegisteredItemFilter(new ItemFilterCache(searchTokens.get(0))));
return new IsRegisteredItemFilter(searchTokens.get(0));
} else {
filtersCache.put(
filterText,
new IsRegisteredItemFilter(new ItemFilterCache(new AnyMultiItemFilter(searchTokens))));
return new IsRegisteredItemFilter(new AnyMultiItemFilter(searchTokens));
}
}
});
return filtersCache.get(filterText);
}
public Pattern getSplitPattern() {
public List<SearchToken> splitSearchText(String filterText) {
if (filterText.isEmpty()) {
return Collections.emptyList();
}
final List<SearchToken> tokens = new ArrayList<>();
final String prefixes = getPrefixes();
final int spaceMode = NEIClientConfig.getIntSetting("inventory.search.spaceMode");
// The regular expression first tries to match a string that starts with a space or the beginning of the string,
// followed by a sequence of characters that do not contain special characters -"@#$%&, and ends with a space
// and the characters -"@#$%& or the end of the string.
final String patternPart1 = "(?<tokenA>(^|\\s+)(?:[^" + Pattern.quote(" -\"" + prefixes)
+ "]).+?(?=\\s+["
+ Pattern.quote("-\"" + prefixes)
+ "]|$))";
// If the first condition is not met, it tries to match a sequence of - characters, followed by @#$%&
// characters, then either a quoted string or non-space characters.
final String patternPart2 = "((?<ignore>-*)(?<firstChar>[" + Pattern.quote(prefixes)
+ "]*)(?<tokenB>\\\".*?(?:\\\"|$)|\\S+\\s*))";
final Pattern pattern = Pattern.compile(spaceMode == 0 ? patternPart2 : (patternPart1 + "|" + patternPart2));
final Matcher filterMatcher = pattern.matcher(filterText);
while (filterMatcher.find()) {
String firstChar = filterMatcher.group("firstChar");
SearchToken token = new SearchToken();
token.start = filterMatcher.start();
token.end = filterMatcher.end();
token.ignore = "-".equals(filterMatcher.group("ignore"));
token.rawText = spaceMode == 0 ? null : filterMatcher.group("tokenA");
if (firstChar != null && !firstChar.isEmpty()) {
token.firstChar = firstChar.charAt(0);
}
if (token.rawText == null) { // spaceMode == 0
token.rawText = filterMatcher.group("tokenB");
token.quotes = token.rawText.length() > 1 && token.rawText.startsWith("\"")
&& token.rawText.endsWith("\"");
if (token.quotes) {
token.rawText = token.rawText.substring(1, token.rawText.length() - 1);
}
token.words = new String[] { token.rawText.trim() };
} else if (spaceMode == 2) {
token.words = token.rawText.trim().split("\\s+");
} else {
token.words = new String[] { token.rawText.trim() };
}
tokens.add(token);
}
return tokens;
}
private String getPrefixes() {
StringBuilder prefixes = new StringBuilder().append('\0');
for (ISearchParserProvider provider : getProviders()) {
@@ -208,14 +248,11 @@ public class SearchTokenParser {
}
}
return Pattern.compile("((-*)([" + Pattern.quote(prefixes.toString()) + "]*)(\\\".*?(?:\\\"|$)|\\S+))");
return prefixes.toString();
}
public char getRedefinedPrefix(char prefix) {
if (this.prefixRedefinitions.containsKey(prefix)) {
return this.prefixRedefinitions.get(prefix);
}
return prefix;
return this.prefixRedefinitions.getOrDefault(prefix, prefix);
}
private ItemFilter parseSearchText(String filterText) {
@@ -224,28 +261,19 @@ public class SearchTokenParser {
return null;
}
final Matcher filterMatcher = getSplitPattern().matcher(filterText);
final AllMultiItemFilter searchTokens = new AllMultiItemFilter();
final List<SearchToken> tokens = splitSearchText(filterText);
while (filterMatcher.find()) {
boolean ignore = "-".equals(filterMatcher.group(2));
String firstChar = filterMatcher.group(3);
String token = filterMatcher.group(4);
boolean quotes = token.length() > 1 && token.startsWith("\"") && token.endsWith("\"");
for (SearchToken token : tokens) {
if (!token.rawText.isEmpty()) {
ItemFilter result = parseToken(token);
if (quotes) {
token = token.substring(1, token.length() - 1);
}
if (!token.isEmpty()) {
ItemFilter result = parseToken(firstChar, token);
if (ignore) {
if (token.ignore) {
searchTokens.filters.add(new NegatedItemFilter(result));
} else {
searchTokens.filters.add(result);
}
} else if (!ignore) {
} else if (!token.ignore) {
searchTokens.filters.add(new NothingItemFilter());
}
}
@@ -253,17 +281,17 @@ public class SearchTokenParser {
return searchTokens;
}
private ItemFilter parseToken(String firstChar, String token) {
final ISearchParserProvider provider = firstChar.isEmpty() ? null : this.getProvider(firstChar.charAt(0));
private ItemFilter parseToken(SearchToken token) {
final ISearchParserProvider provider = token.firstChar == null ? null : this.getProvider(token.firstChar);
if (provider == null || provider.getSearchMode() == SearchMode.NEVER) {
final List<ItemFilter> filters = new ArrayList<>();
for (ISearchParserProvider _provider : getProviders()) {
if (_provider.getSearchMode() == SearchMode.ALWAYS) {
ItemFilter filter = _provider.getFilter(token);
AllMultiItemFilter filter = generateFilters(_provider, token.words);
if (filter != null) {
if (!filter.filters.isEmpty()) {
filters.add(filter);
}
}
@@ -271,7 +299,21 @@ public class SearchTokenParser {
return filters.isEmpty() ? new NothingItemFilter() : new AnyMultiItemFilter(filters);
} else {
return provider.getFilter(token);
return generateFilters(provider, token.words);
}
}
private AllMultiItemFilter generateFilters(ISearchParserProvider provider, String[] words) {
final AllMultiItemFilter filters = new AllMultiItemFilter();
for (String work : words) {
final ItemFilter filter = provider.getFilter(work);
if (filter != null) {
filters.filters.add(filter);
}
}
return filters;
}
}
@@ -75,26 +75,25 @@ public abstract class OptionButton extends Option {
}
public String getTooltip() {
String tip = null;
if (tooltip != null) {
String s = translateN(tooltip);
if (!s.equals(namespaced(tooltip))) {
tip = s;
return s;
}
}
if (tip == null && getPrefix() != null) {
if (getPrefix() != null) {
final int width = getStringWidth(getPrefix());
final Rectangle b = buttonSize();
if (width >= b.x) {
tip = translateN(name);
return translateN(name);
}
}
return tip;
return null;
}
public void drawPrefix() {
@@ -29,6 +29,18 @@ public class OptionCycled extends OptionButton {
return prefixed ? translateN(name) : null;
}
@Override
public String getTooltip() {
String tooltip = name + "." + value() + ".tip";
String s = translateN(tooltip);
if (!s.equals(namespaced(tooltip))) {
return s;
}
return super.getTooltip();
}
@Override
public boolean onClick(int button) {
return cycle();
@@ -43,6 +43,7 @@ import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemStackSet;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.SearchField;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.search.TooltipFilter;
import codechicken.nei.util.ReadableNumberConverter;
@@ -55,6 +56,7 @@ public class GuiContainerManager {
public void onResourceManagerReload(IResourceManager p_110549_1_) {
renderingErrorItems.clear();
TooltipFilter.populateSearchMap();
SearchField.searchParser.clearCache();
}
}
@@ -1,7 +1,6 @@
package codechicken.nei.search;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
import net.minecraft.item.ItemStack;
@@ -9,13 +8,12 @@ import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.ItemList;
import codechicken.nei.ItemStackMap;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.guihook.GuiContainerManager;
public class TooltipFilter implements ItemFilter {
private static final ItemStackMap<String> itemSearchNames = new ItemStackMap<>();
private static final ReentrantLock lock = new ReentrantLock();
private final Pattern pattern;
@@ -36,28 +34,32 @@ public class TooltipFilter implements ItemFilter {
}
protected static String getSearchTooltip(ItemStack stack) {
lock.lock();
String tooltip = itemSearchNames.get(stack);
try {
String tooltip = itemSearchNames.get(stack);
if (tooltip == null) {
tooltip = getTooltip(stack.copy());
if (tooltip == null) {
tooltip = getTooltip(stack.copy());
synchronized (itemSearchNames) {
itemSearchNames.put(stack, tooltip);
}
return tooltip;
} catch (Throwable th) {
th.printStackTrace();
return "";
} finally {
lock.unlock();
}
return tooltip;
}
private static String getTooltip(ItemStack itemstack) {
final List<String> list = GuiContainerManager.itemDisplayNameMultiline(itemstack, null, true);
return EnumChatFormatting.getTextWithoutFormattingCodes(String.join("\n", list.subList(1, list.size())));
try {
List<String> namelist = itemstack.getTooltip(NEIClientUtils.mc().thePlayer, false);
if (namelist.size() > 1) {
return EnumChatFormatting
.getTextWithoutFormattingCodes(String.join("\n", namelist.subList(1, namelist.size())));
}
} catch (Throwable ignored) {}
return "";
}
}
@@ -224,6 +224,13 @@ nei.options.inventory.search.patternMode=Search Mode
nei.options.inventory.search.patternMode.0=Plain
nei.options.inventory.search.patternMode.1=Extended
nei.options.inventory.search.patternMode.2=Regex
nei.options.inventory.search.spaceMode=Space Works like
nei.options.inventory.search.spaceMode.0=AND
nei.options.inventory.search.spaceMode.0.tip=Space between non-prefixed tokens works like "AND"
nei.options.inventory.search.spaceMode.1=Space
nei.options.inventory.search.spaceMode.1.tip=Space between non-prefixed tokens works like "space"
nei.options.inventory.search.spaceMode.2=AND-X
nei.options.inventory.search.spaceMode.2.tip=Space between non-prefixed tokens works like "AND" but all tokens must be within the same category
nei.options.inventory.search.quoteDropItemName=Quote Drop Item Name
nei.options.inventory.search.quoteDropItemName.true=Yes
nei.options.inventory.search.quoteDropItemName.false=No