001/* 002 * This file is part of Baritone. 003 * 004 * Baritone is free software: you can redistribute it and/or modify 005 * it under the terms of the GNU Lesser General Public License as published by 006 * the Free Software Foundation, either version 3 of the License, or 007 * (at your option) any later version. 008 * 009 * Baritone is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public License 015 * along with Baritone. If not, see <https://www.gnu.org/licenses/>. 016 */ 017 018package baritone.api.command.helpers; 019 020import baritone.api.BaritoneAPI; 021import baritone.api.Settings; 022import baritone.api.command.argument.IArgConsumer; 023import baritone.api.command.manager.ICommandManager; 024import baritone.api.event.events.TabCompleteEvent; 025import baritone.api.utils.SettingsUtil; 026import java.util.Comparator; 027import java.util.List; 028import java.util.Locale; 029import java.util.function.Function; 030import java.util.function.Predicate; 031import java.util.stream.Stream; 032import net.minecraft.resources.ResourceLocation; 033 034/** 035 * The {@link TabCompleteHelper} is a <b>single-use</b> object that helps you handle tab completion. It includes helper 036 * methods for appending and prepending streams, sorting, filtering by prefix, and so on. 037 * <p> 038 * The recommended way to use this class is: 039 * <ul> 040 * <li>Create a new instance with the empty constructor</li> 041 * <li>Use {@code append}, {@code prepend} or {@code add<something>} methods to add completions</li> 042 * <li>Sort using {@link #sort(Comparator)} or {@link #sortAlphabetically()} and then filter by prefix using 043 * {@link #filterPrefix(String)}</li> 044 * <li>Get the stream using {@link #stream()}</li> 045 * <li>Pass it up to whatever's calling your tab complete function (i.e. 046 * {@link ICommandManager#tabComplete(String)} or {@link IArgConsumer}#tabCompleteDatatype(IDatatype)})</li> 047 * </ul> 048 * <p> 049 * For advanced users: if you're intercepting {@link TabCompleteEvent}s directly, use {@link #build()} instead for an 050 * array. 051 */ 052public class TabCompleteHelper { 053 054 private Stream<String> stream; 055 056 public TabCompleteHelper(String[] base) { 057 stream = Stream.of(base); 058 } 059 060 public TabCompleteHelper(List<String> base) { 061 stream = base.stream(); 062 } 063 064 public TabCompleteHelper() { 065 stream = Stream.empty(); 066 } 067 068 /** 069 * Appends the specified stream to this {@link TabCompleteHelper} and returns it for chaining 070 * 071 * @param source The stream to append 072 * @return This {@link TabCompleteHelper} after having appended the stream 073 * @see #append(String...) 074 * @see #append(Class) 075 */ 076 public TabCompleteHelper append(Stream<String> source) { 077 stream = Stream.concat(stream, source); 078 return this; 079 } 080 081 /** 082 * Appends the specified strings to this {@link TabCompleteHelper} and returns it for chaining 083 * 084 * @param source The stream to append 085 * @return This {@link TabCompleteHelper} after having appended the strings 086 * @see #append(Stream) 087 * @see #append(Class) 088 */ 089 public TabCompleteHelper append(String... source) { 090 return append(Stream.of(source)); 091 } 092 093 /** 094 * Appends all values of the specified enum to this {@link TabCompleteHelper} and returns it for chaining 095 * 096 * @param num The enum to append the values of 097 * @return This {@link TabCompleteHelper} after having appended the values 098 * @see #append(Stream) 099 * @see #append(String...) 100 */ 101 public TabCompleteHelper append(Class<? extends Enum<?>> num) { 102 return append( 103 Stream.of(num.getEnumConstants()) 104 .map(Enum::name) 105 .map(String::toLowerCase) 106 ); 107 } 108 109 /** 110 * Prepends the specified stream to this {@link TabCompleteHelper} and returns it for chaining 111 * 112 * @param source The stream to prepend 113 * @return This {@link TabCompleteHelper} after having prepended the stream 114 * @see #prepend(String...) 115 * @see #prepend(Class) 116 */ 117 public TabCompleteHelper prepend(Stream<String> source) { 118 stream = Stream.concat(source, stream); 119 return this; 120 } 121 122 /** 123 * Prepends the specified strings to this {@link TabCompleteHelper} and returns it for chaining 124 * 125 * @param source The stream to prepend 126 * @return This {@link TabCompleteHelper} after having prepended the strings 127 * @see #prepend(Stream) 128 * @see #prepend(Class) 129 */ 130 public TabCompleteHelper prepend(String... source) { 131 return prepend(Stream.of(source)); 132 } 133 134 /** 135 * Prepends all values of the specified enum to this {@link TabCompleteHelper} and returns it for chaining 136 * 137 * @param num The enum to prepend the values of 138 * @return This {@link TabCompleteHelper} after having prepended the values 139 * @see #prepend(Stream) 140 * @see #prepend(String...) 141 */ 142 public TabCompleteHelper prepend(Class<? extends Enum<?>> num) { 143 return prepend( 144 Stream.of(num.getEnumConstants()) 145 .map(Enum::name) 146 .map(String::toLowerCase) 147 ); 148 } 149 150 /** 151 * Apply the specified {@code transform} to every element <b>currently</b> in this {@link TabCompleteHelper} and 152 * return this object for chaining 153 * 154 * @param transform The transform to apply 155 * @return This {@link TabCompleteHelper} 156 */ 157 public TabCompleteHelper map(Function<String, String> transform) { 158 stream = stream.map(transform); 159 return this; 160 } 161 162 /** 163 * Apply the specified {@code filter} to every element <b>currently</b> in this {@link TabCompleteHelper} and return 164 * this object for chaining 165 * 166 * @param filter The filter to apply 167 * @return This {@link TabCompleteHelper} 168 */ 169 public TabCompleteHelper filter(Predicate<String> filter) { 170 stream = stream.filter(filter); 171 return this; 172 } 173 174 /** 175 * Apply the specified {@code sort} to every element <b>currently</b> in this {@link TabCompleteHelper} and return 176 * this object for chaining 177 * 178 * @param comparator The comparator to use 179 * @return This {@link TabCompleteHelper} 180 */ 181 public TabCompleteHelper sort(Comparator<String> comparator) { 182 stream = stream.sorted(comparator); 183 return this; 184 } 185 186 /** 187 * Sort every element <b>currently</b> in this {@link TabCompleteHelper} alphabetically and return this object for 188 * chaining 189 * 190 * @return This {@link TabCompleteHelper} 191 */ 192 public TabCompleteHelper sortAlphabetically() { 193 return sort(String.CASE_INSENSITIVE_ORDER); 194 } 195 196 /** 197 * Filter out any element that doesn't start with {@code prefix} and return this object for chaining 198 * 199 * @param prefix The prefix to filter for 200 * @return This {@link TabCompleteHelper} 201 */ 202 public TabCompleteHelper filterPrefix(String prefix) { 203 return filter(x -> x.toLowerCase(Locale.US).startsWith(prefix.toLowerCase(Locale.US))); 204 } 205 206 /** 207 * Filter out any element that doesn't start with {@code prefix} and return this object for chaining 208 * <p> 209 * Assumes every element in this {@link TabCompleteHelper} is a {@link ResourceLocation} 210 * 211 * @param prefix The prefix to filter for 212 * @return This {@link TabCompleteHelper} 213 */ 214 public TabCompleteHelper filterPrefixNamespaced(String prefix) { 215 ResourceLocation loc = ResourceLocation.tryParse(prefix); 216 if (loc == null) { 217 stream = Stream.empty(); 218 return this; 219 } 220 return filterPrefix(loc.toString()); 221 } 222 223 /** 224 * @return An array containing every element in this {@link TabCompleteHelper} 225 * @see #stream() 226 */ 227 public String[] build() { 228 return stream.toArray(String[]::new); 229 } 230 231 /** 232 * @return A stream containing every element in this {@link TabCompleteHelper} 233 * @see #build() 234 */ 235 public Stream<String> stream() { 236 return stream; 237 } 238 239 /** 240 * Appends every command in the specified {@link ICommandManager} to this {@link TabCompleteHelper} 241 * 242 * @param manager A command manager 243 * @return This {@link TabCompleteHelper} 244 */ 245 public TabCompleteHelper addCommands(ICommandManager manager) { 246 return append(manager.getRegistry().descendingStream() 247 .flatMap(command -> command.getNames().stream()) 248 .distinct() 249 ); 250 } 251 252 /** 253 * Appends every setting in the {@link Settings} to this {@link TabCompleteHelper} 254 * 255 * @return This {@link TabCompleteHelper} 256 */ 257 public TabCompleteHelper addSettings() { 258 return append( 259 BaritoneAPI.getSettings().allSettings.stream() 260 .filter(s -> !s.isJavaOnly()) 261 .map(Settings.Setting::getName) 262 .sorted(String.CASE_INSENSITIVE_ORDER) 263 ); 264 } 265 266 /** 267 * Appends every modified setting in the {@link Settings} to this {@link TabCompleteHelper} 268 * 269 * @return This {@link TabCompleteHelper} 270 */ 271 public TabCompleteHelper addModifiedSettings() { 272 return append( 273 SettingsUtil.modifiedSettings(BaritoneAPI.getSettings()).stream() 274 .map(Settings.Setting::getName) 275 .sorted(String.CASE_INSENSITIVE_ORDER) 276 ); 277 } 278 279 /** 280 * Appends every {@link Boolean} setting in the {@link Settings} to this {@link TabCompleteHelper} 281 * 282 * @return This {@link TabCompleteHelper} 283 */ 284 public TabCompleteHelper addToggleableSettings() { 285 return append( 286 BaritoneAPI.getSettings().getAllValuesByType(Boolean.class).stream() 287 .map(Settings.Setting::getName) 288 .sorted(String.CASE_INSENSITIVE_ORDER) 289 ); 290 } 291}