Skip to content

Commit 7052083

Browse files
authored
Improve the /cwiki command (#775)
* Add opening looked up article's URL * Add searching article names * Modularize the WikiRetriever code and fix minor bugs * Improve searching and fix minor bugs * Small fix for tolerating more inputs * Set Locale to ROOT
1 parent 971da37 commit 7052083

3 files changed

Lines changed: 127 additions & 10 deletions

File tree

src/main/java/net/earthcomputer/clientcommands/command/WikiCommand.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,54 @@
55
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
66
import net.earthcomputer.clientcommands.features.WikiRetriever;
77
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
8+
import net.minecraft.ChatFormatting;
9+
import net.minecraft.network.chat.ClickEvent;
810
import net.minecraft.network.chat.Component;
11+
import org.jspecify.annotations.Nullable;
12+
13+
import java.net.URI;
14+
import java.net.URLEncoder;
15+
import java.nio.charset.StandardCharsets;
916

1017
import static com.mojang.brigadier.arguments.StringArgumentType.*;
1118
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*;
1219

1320
public class WikiCommand {
1421
private static final SimpleCommandExceptionType FAILED_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.cwiki.failed"));
1522

23+
private static final String WIKI_HOST = "https://minecraft.wiki/";
24+
private static final String WIKI_ARTICLE = WIKI_HOST + "w/%s";
25+
26+
1627
public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) {
1728
dispatcher.register(literal("cwiki")
1829
.then(argument("page", greedyString())
1930
.executes(ctx -> displayWikiPage(ctx.getSource(), getString(ctx, "page")))));
2031
}
2132

33+
@Nullable
34+
private static Component getLinkComponent(String page) {
35+
String title = WikiRetriever.searchArticleName(page);
36+
if (title == null) {
37+
return null;
38+
}
39+
40+
String pageName = URLEncoder.encode(title, StandardCharsets.UTF_8).replace('+', '_');
41+
String url = String.format(WIKI_ARTICLE, pageName);
42+
URI uri = URI.create(url);
43+
44+
ClickEvent clickEvent = new ClickEvent.OpenUrl(uri);
45+
46+
return Component.translatable("commands.cwiki.openArticle")
47+
.withStyle(style -> style
48+
.withClickEvent(clickEvent)
49+
.withColor(ChatFormatting.GREEN)
50+
.withUnderlined(true)
51+
);
52+
}
53+
2254
private static int displayWikiPage(FabricClientCommandSource source, String page) throws CommandSyntaxException {
2355
String content = WikiRetriever.getWikiSummary(page);
24-
2556
if (content == null) {
2657
throw FAILED_EXCEPTION.create();
2758
}
@@ -31,6 +62,13 @@ private static int displayWikiPage(FabricClientCommandSource source, String page
3162
source.sendFeedback(Component.literal(line));
3263
}
3364

65+
Component link = getLinkComponent(page);
66+
if (link == null) {
67+
throw FAILED_EXCEPTION.create();
68+
}
69+
70+
source.sendFeedback(link);
71+
3472
return content.length();
3573
}
3674

src/main/java/net/earthcomputer/clientcommands/features/WikiRetriever.java

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,18 @@
1313
import java.net.URL;
1414
import java.net.URLEncoder;
1515
import java.nio.charset.StandardCharsets;
16+
import java.util.Arrays;
17+
import java.util.List;
1618
import java.util.Locale;
1719
import java.util.Map;
1820
import java.util.regex.Matcher;
1921
import java.util.regex.Pattern;
22+
import java.util.stream.Collectors;
2023

2124
public class WikiRetriever {
2225

2326
private static final String WIKI_HOST = "https://minecraft.wiki/";
27+
private static final String SEARCH_QUERY = WIKI_HOST + "api.php?action=query&list=search&srlimit=1&srprop=snippet&format=json&srsearch=%s";
2428
private static final String PAGE_SUMMARY_QUERY = WIKI_HOST + "api.php?action=query&prop=extracts&exintro=true&format=json&titles=%s";
2529
private static final Pattern HTML_TAG_PATTERN = Pattern.compile("<\\s*(/)?\\s*(\\w+).*?>|<!--.*?-->|\n", Pattern.DOTALL);
2630
private static final ChatFormatting CODE_COLOR = ChatFormatting.DARK_GREEN;
@@ -184,19 +188,78 @@ public static String decode(String html) {
184188
}
185189

186190
@Nullable
187-
public static String getWikiSummary(String pageName) {
191+
public static QueryResult getResult(URL url) {
192+
QueryResult result;
193+
try (InputStream in = url.openConnection().getInputStream()) {
194+
result = GSON.fromJson(new InputStreamReader(in), QueryResult.class);
195+
} catch (IOException e) {
196+
return null;
197+
}
198+
return result;
199+
}
200+
201+
@Nullable
202+
public static URL buildURL(String page, String query) {
203+
String result = Arrays.stream(page.split("\\s+"))
204+
.map(w -> w.substring(0, 1).toUpperCase(Locale.ROOT)
205+
+ w.substring(1).toLowerCase(Locale.ROOT))
206+
.collect(Collectors.joining(" "));
207+
208+
188209
URL url;
189210
try {
190-
String encodedPage = URLEncoder.encode(pageName, StandardCharsets.UTF_8);
191-
url = URI.create(String.format(PAGE_SUMMARY_QUERY, encodedPage)).toURL();
211+
String encodedPage = URLEncoder.encode(result, StandardCharsets.UTF_8);
212+
url = URI.create(String.format(query, encodedPage)).toURL();
192213
} catch (MalformedURLException e) {
193214
return null;
194215
}
216+
return url;
217+
}
218+
219+
@Nullable
220+
public static String searchArticleName(String pageInput){
221+
URL url = buildURL(pageInput.trim(), SEARCH_QUERY);
222+
if (url == null) {
223+
return null;
224+
}
195225

196-
QueryResult result;
197-
try (InputStream in = url.openConnection().getInputStream()) {
198-
result = GSON.fromJson(new InputStreamReader(in), QueryResult.class);
199-
} catch (IOException e) {
226+
QueryResult result = getResult(url);
227+
if (result == null) {
228+
return null;
229+
}
230+
231+
var query = result.query;
232+
if (query == null) {
233+
return null;
234+
}
235+
236+
var search = query.search;
237+
var searchinfo = query.searchinfo;
238+
if (search == null || search.isEmpty() || searchinfo == null || searchinfo.totalhits == 0) {
239+
return null;
240+
}
241+
242+
if (searchinfo.suggestion != null) {
243+
return searchinfo.suggestion;
244+
}
245+
246+
return query.search.getFirst().title;
247+
}
248+
249+
@Nullable
250+
public static String getWikiSummary(String pageName) {
251+
String title = searchArticleName(pageName);
252+
if (title == null) {
253+
return null;
254+
}
255+
256+
URL url = buildURL(title, PAGE_SUMMARY_QUERY);
257+
if (url == null) {
258+
return null;
259+
}
260+
261+
QueryResult result = getResult(url);
262+
if (result == null) {
200263
return null;
201264
}
202265

@@ -212,12 +275,12 @@ public static String getWikiSummary(String pageName) {
212275
}
213276

214277
@SuppressWarnings("unused")
215-
private static class QueryResult {
278+
public static class QueryResult {
216279
@Nullable
217280
public String batchcomplete;
218281
@Nullable
219282
public Query query;
220-
private static class Query {
283+
public static class Query {
221284
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
222285
@Nullable
223286
private Map<String, Page> pages;
@@ -230,6 +293,21 @@ private static class Page {
230293
@Nullable
231294
public String missing;
232295
}
296+
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
297+
@Nullable
298+
private List<Search> search;
299+
private static class Search {
300+
@Nullable
301+
public String title;
302+
}
303+
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
304+
@Nullable
305+
private SearchInfo searchinfo;
306+
private static class SearchInfo {
307+
public int totalhits;
308+
@Nullable
309+
public String suggestion;
310+
}
233311
}
234312
}
235313

src/main/resources/assets/clientcommands/lang/en_us.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@
317317

318318
"commands.cwiki.failed": "Could not retrieve wiki content",
319319
"commands.cwiki.noContent": "There is no introductory paragraph in that article",
320+
"commands.cwiki.openArticle": "[Open article]",
320321

321322
"connectFourGame.draw": "Draw!",
322323
"connectFourGame.lost": "Lost!",

0 commit comments

Comments
 (0)