1414import java .io .IOException ;
1515import java .io .InputStream ;
1616import java .util .Arrays ;
17+ import java .util .Collections ;
1718import java .util .Comparator ;
19+ import java .util .HashSet ;
1820import java .util .List ;
1921import java .util .Map ;
22+ import java .util .Set ;
23+ import java .util .concurrent .CompletableFuture ;
2024import java .util .stream .Collectors ;
2125
2226/**
2327 * The !docs command which is used to show links to Javacord's JavaDocs.
2428 */
2529public class DocsCommand implements CommandExecutor {
2630
31+ /**
32+ * The parameters that indicate searching for class names only.
33+ */
34+ private static final Set <String > classParams = new HashSet <>(Arrays .asList ("classes" , "class" , "c" ));
35+ /**
36+ * The parameters that indicate searching for method names only.
37+ */
38+ private static final Set <String > methodParams = new HashSet <>(Arrays .asList ("methods" , "method" , "m" ));
39+ /**
40+ * The parameters that indicate also searching internal packages and the core docs.
41+ */
42+ private static final Set <String > includeAllParams = new HashSet <>(Arrays .asList ("all" , "a" ));
43+
2744 /**
2845 * Executes the {@code !docs} command.
2946 *
@@ -42,16 +59,21 @@ public void onCommand(TextChannel channel, String[] args) throws IOException {
4259 .addField ("Latest release version" , "https://docs.javacord.org/api/v/latest" )
4360 .addField ("Latest snapshot" , "https://docs.javacord.org/api/build/latest" )
4461 .addField ("Hint" , "You can search the docs using `!docs [method|class] <search>`" );
45- } else { // Search
46- if (args [0 ].matches ("(classes|class|c)" )) { // Search for a class
47- String searchString = String .join (" " , Arrays .copyOfRange (args , 1 , args .length ));
48- populateClasses (channel .getApi (), embed , searchString );
49- } else if (args [0 ].matches ("(methods|method|m)" )) { // Search for a method
50- String searchString = String .join (" " , Arrays .copyOfRange (args , 1 , args .length ));
51- populateMethods (channel .getApi (), embed , searchString );
62+ } else if (args .length == 1 ) { // Basic search - methods without internals
63+ populateMethods (channel .getApi (), embed , args [0 ], false );
64+ } else { // Extended search
65+ if (classParams .contains (args [0 ])) { // Search for a class
66+ boolean searchAll = args .length > 2 && includeAllParams .contains (args [1 ]);
67+ String searchString = String .join (" " , Arrays .copyOfRange (args , searchAll ? 2 : 1 , args .length ));
68+ populateClasses (channel .getApi (), embed , searchString , searchAll );
69+ } else if (methodParams .contains (args [0 ])) { // Search for a method
70+ boolean searchAll = args .length > 2 && includeAllParams .contains (args [1 ]);
71+ String searchString = String .join (" " , Arrays .copyOfRange (args , searchAll ? 2 : 1 , args .length ));
72+ populateMethods (channel .getApi (), embed , searchString , searchAll );
5273 } else { // Search for a method
53- String searchString = String .join (" " , args );
54- populateMethods (channel .getApi (), embed , searchString );
74+ boolean searchAll = includeAllParams .contains (args [0 ]);
75+ String searchString = String .join (" " , Arrays .copyOfRange (args , searchAll ? 1 : 0 , args .length ));
76+ populateMethods (channel .getApi (), embed , searchString , searchAll );
5577 }
5678 }
5779 channel .sendMessage (embed ).join ();
@@ -70,10 +92,22 @@ public void onCommand(TextChannel channel, String[] args) throws IOException {
7092 * @param embed The embed to populate.
7193 * @param searchString A search string.
7294 */
73- private void populateMethods (DiscordApi api , EmbedBuilder embed , String searchString ) {
74- Map <String , List <JavadocMethod >> methods = new JavadocParser (api , JavadocParser .getLatestJavaDocs (api ).join ())
75- .getMethods ().join ().stream ()
95+ private void populateMethods (DiscordApi api , EmbedBuilder embed , String searchString , boolean includeAll ) {
96+ CompletableFuture <Set <JavadocMethod >> apiMethods = JavadocParser .getLatestJavaDocs (api )
97+ .thenApply (urlString -> new JavadocParser (api , urlString ))
98+ .thenCompose (JavadocParser ::getMethods );
99+ CompletableFuture <Set <JavadocMethod >> coreMethods = (includeAll )
100+ ? JavadocParser .getLatestCoreJavaDocs (api )
101+ .thenApply (urlString -> new JavadocParser (api , urlString ))
102+ .thenCompose (JavadocParser ::getMethods )
103+ : CompletableFuture .completedFuture (Collections .emptySet ());
104+
105+ Map <String , List <JavadocMethod >> methods = apiMethods .thenCombine (coreMethods , this ::unionOf ).join ().stream ()
76106 .filter (method -> method .getFullName ().toLowerCase ().contains (searchString .toLowerCase ()))
107+ .filter (method -> {
108+ String packageName = method .getPackageName ();
109+ return includeAll || !(packageName .endsWith (".internal" ) || packageName .contains (".internal." ));
110+ })
77111 .sorted (Comparator .comparingInt (method -> method .getName ().length ()))
78112 .collect (Collectors .groupingBy (JavadocMethod ::getClassName ));
79113
@@ -115,17 +149,47 @@ private void populateMethods(DiscordApi api, EmbedBuilder embed, String searchSt
115149 }
116150 }
117151
152+ /**
153+ * Union operation for sets.
154+ *
155+ * @param set1 First set.
156+ * @param set2 Second set.
157+ * @param <T> Type of set content.
158+ * @return The union of the two sets.
159+ */
160+ private <T > Set <T > unionOf (Set <T > set1 , Set <T > set2 ) {
161+ if (set2 .isEmpty ()) {
162+ return set1 ;
163+ } else {
164+ Set <T > union = new HashSet <>(set1 );
165+ union .addAll (set2 );
166+ return union ;
167+ }
168+ }
169+
118170 /**
119171 * Populates the classes field inside the given embed.
120172 *
121173 * @param api A discord api instance.
122174 * @param embed The embed to populate.
123175 * @param searchString A search string.
124176 */
125- private void populateClasses (DiscordApi api , EmbedBuilder embed , String searchString ) {
126- List <JavadocClass > classes = new JavadocParser (api , JavadocParser .getLatestJavaDocs (api ).join ())
127- .getClasses ().join ().stream ()
177+ private void populateClasses (DiscordApi api , EmbedBuilder embed , String searchString , boolean includeAll ) {
178+ CompletableFuture <Set <JavadocClass >> apiClasses = JavadocParser .getLatestJavaDocs (api )
179+ .thenApply (urlString -> new JavadocParser (api , urlString ))
180+ .thenCompose (JavadocParser ::getClasses );
181+ CompletableFuture <Set <JavadocClass >> coreClasses = (includeAll )
182+ ? JavadocParser .getLatestCoreJavaDocs (api )
183+ .thenApply (urlString -> new JavadocParser (api , urlString ))
184+ .thenCompose (JavadocParser ::getClasses )
185+ : CompletableFuture .completedFuture (Collections .emptySet ());
186+
187+ List <JavadocClass > classes = apiClasses .thenCombine (coreClasses , this ::unionOf ).join ().stream ()
128188 .filter (clazz -> clazz .getName ().toLowerCase ().contains (searchString .toLowerCase ()))
189+ .filter (clazz -> {
190+ String packageName = clazz .getPackageName ();
191+ return includeAll || !(packageName .endsWith (".internal" ) || packageName .contains (".internal." ));
192+ })
129193 .sorted (Comparator .comparingInt (clazz -> clazz .getName ().length ()))
130194 .collect (Collectors .toList ());
131195
@@ -138,19 +202,22 @@ private void populateClasses(DiscordApi api, EmbedBuilder embed, String searchSt
138202 StringBuilder strBuilder = new StringBuilder ();
139203 int counter = 0 ;
140204 for (JavadocClass clazz : classes ) {
205+ if (strBuilder .length () > 0 ) {
206+ strBuilder .append (", " );
207+ }
141208 strBuilder .append ("[" )
142209 .append (clazz .getName ())
143210 .append ("](" )
144211 .append (clazz .getFullUrl ())
145- .append ("), " );
212+ .append (")" );
146213 counter ++;
147214 if (strBuilder .length () > 1950 ) { // Prevent hitting the description size limit
148215 break ;
149216 }
150217 }
151218
152219 if (classes .size () - counter > 0 ) {
153- strBuilder .append ("and " ).append (classes .size () - counter ).append (" more ..." );
220+ strBuilder .append ("\n and " ).append (classes .size () - counter ).append (" more ..." );
154221 }
155222
156223 embed .setDescription (strBuilder .toString ());
0 commit comments