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 Space Mode Settings to Search #571

Merged
merged 2 commits into from
Dec 23, 2024
Merged
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
18 changes: 18 additions & 0 deletions src/main/java/codechicken/nei/NEIClientConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ public boolean onClick(int button) {
}

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);
Expand All @@ -468,6 +469,7 @@ public boolean onClick(int button) {
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);
Expand All @@ -483,6 +485,22 @@ public boolean onClick(int button) {

});

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) {
Expand Down
49 changes: 18 additions & 31 deletions src/main/java/codechicken/nei/SearchTextFormatter.java
Original file line number Diff line number Diff line change
@@ -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 {

Expand All @@ -17,63 +17,50 @@ public SearchTextFormatter(SearchTokenParser searchParser) {
}

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();
}
}
130 changes: 101 additions & 29 deletions src/main/java/codechicken/nei/SearchTokenParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -21,8 +22,6 @@
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 {

Expand All @@ -41,6 +40,20 @@ public static SearchMode fromInt(int value) {
}
}

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);
Expand Down Expand Up @@ -99,7 +112,7 @@ protected boolean removeEldestEntry(Map.Entry<String, ItemFilter> eldest) {

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;
Expand Down Expand Up @@ -169,7 +182,64 @@ public synchronized ItemFilter getFilter(String 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()) {
Expand All @@ -178,14 +248,11 @@ public Pattern getSplitPattern() {
}
}

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) {
Expand All @@ -194,54 +261,59 @@ private ItemFilter parseSearchText(String filterText) {
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("\"");

if (quotes) {
token = token.substring(1, token.length() - 1);
}

if (!token.isEmpty()) {
ItemFilter result = parseToken(firstChar, token);
for (SearchToken token : tokens) {
if (!token.rawText.isEmpty()) {
ItemFilter result = parseToken(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());
}
}

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);
}
}
}

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;
}
}
9 changes: 4 additions & 5 deletions src/main/java/codechicken/nei/config/OptionButton.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,25 @@ public String getButtonText() {
}

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() {
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/codechicken/nei/config/OptionCycled.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ public String getPrefix() {
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();
Expand Down
Loading
Loading