Bukkit-API  1.7.9-R0.2
The inofficial Bukkit-API
HelpCommand.java
1 package org.bukkit.command.defaults;
2 
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Set;
9 import java.util.TreeSet;
10 
11 import org.apache.commons.lang.ArrayUtils;
12 import org.apache.commons.lang.StringUtils;
13 import org.apache.commons.lang.Validate;
14 import org.apache.commons.lang.math.NumberUtils;
15 import org.bukkit.Bukkit;
16 import org.bukkit.ChatColor;
19 import org.bukkit.help.HelpMap;
20 import org.bukkit.help.HelpTopic;
24 
25 import com.google.common.collect.ImmutableList;
26 
27 public class HelpCommand extends VanillaCommand {
28  public HelpCommand() {
29  super("help");
30  this.description = "Shows the help menu";
31  this.usageMessage = "/help <pageNumber>\n/help <topic>\n/help <topic> <pageNumber>";
32  this.setAliases(Arrays.asList(new String[] { "?" }));
33  this.setPermission("bukkit.command.help");
34  }
35 
36  @Override
37  public boolean execute(CommandSender sender, String currentAlias, String[] args) {
38  if (!testPermission(sender)) return true;
39 
40  String command;
41  int pageNumber;
42  int pageHeight;
43  int pageWidth;
44 
45  if (args.length == 0) {
46  command = "";
47  pageNumber = 1;
48  } else if (NumberUtils.isDigits(args[args.length - 1])) {
49  command = StringUtils.join(ArrayUtils.subarray(args, 0, args.length - 1), " ");
50  try {
51  pageNumber = NumberUtils.createInteger(args[args.length - 1]);
52  } catch (NumberFormatException exception) {
53  pageNumber = 1;
54  }
55  if (pageNumber <= 0) {
56  pageNumber = 1;
57  }
58  } else {
59  command = StringUtils.join(args, " ");
60  pageNumber = 1;
61  }
62 
63  if (sender instanceof ConsoleCommandSender) {
64  pageHeight = ChatPaginator.UNBOUNDED_PAGE_HEIGHT;
65  pageWidth = ChatPaginator.UNBOUNDED_PAGE_WIDTH;
66  } else {
67  pageHeight = ChatPaginator.CLOSED_CHAT_PAGE_HEIGHT - 1;
68  pageWidth = ChatPaginator.GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH;
69  }
70 
71  HelpMap helpMap = Bukkit.getServer().getHelpMap();
72  HelpTopic topic = helpMap.getHelpTopic(command);
73 
74  if (topic == null) {
75  topic = helpMap.getHelpTopic("/" + command);
76  }
77 
78  if (topic == null) {
79  topic = findPossibleMatches(command);
80  }
81 
82  if (topic == null || !topic.canSee(sender)) {
83  sender.sendMessage(ChatColor.RED + "No help for " + command);
84  return true;
85  }
86 
87  ChatPaginator.ChatPage page = ChatPaginator.paginate(topic.getFullText(sender), pageNumber, pageWidth, pageHeight);
88 
89  StringBuilder header = new StringBuilder();
90  header.append(ChatColor.YELLOW);
91  header.append("--------- ");
92  header.append(ChatColor.WHITE);
93  header.append("Help: ");
94  header.append(topic.getName());
95  header.append(" ");
96  if (page.getTotalPages() > 1) {
97  header.append("(");
98  header.append(page.getPageNumber());
99  header.append("/");
100  header.append(page.getTotalPages());
101  header.append(") ");
102  }
103  header.append(ChatColor.YELLOW);
104  for (int i = header.length(); i < ChatPaginator.GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH; i++) {
105  header.append("-");
106  }
107  sender.sendMessage(header.toString());
108 
109  sender.sendMessage(page.getLines());
110 
111  return true;
112  }
113 
114  @Override
115  public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
116  Validate.notNull(sender, "Sender cannot be null");
117  Validate.notNull(args, "Arguments cannot be null");
118  Validate.notNull(alias, "Alias cannot be null");
119 
120  if (args.length == 1) {
121  List<String> matchedTopics = new ArrayList<String>();
122  String searchString = args[0];
123  for (HelpTopic topic : Bukkit.getServer().getHelpMap().getHelpTopics()) {
124  String trimmedTopic = topic.getName().startsWith("/") ? topic.getName().substring(1) : topic.getName();
125 
126  if (trimmedTopic.startsWith(searchString)) {
127  matchedTopics.add(trimmedTopic);
128  }
129  }
130  return matchedTopics;
131  }
132  return ImmutableList.of();
133  }
134 
135  protected HelpTopic findPossibleMatches(String searchString) {
136  int maxDistance = (searchString.length() / 5) + 3;
137  Set<HelpTopic> possibleMatches = new TreeSet<HelpTopic>(HelpTopicComparator.helpTopicComparatorInstance());
138 
139  if (searchString.startsWith("/")) {
140  searchString = searchString.substring(1);
141  }
142 
143  for (HelpTopic topic : Bukkit.getServer().getHelpMap().getHelpTopics()) {
144  String trimmedTopic = topic.getName().startsWith("/") ? topic.getName().substring(1) : topic.getName();
145 
146  if (trimmedTopic.length() < searchString.length()) {
147  continue;
148  }
149 
150  if (Character.toLowerCase(trimmedTopic.charAt(0)) != Character.toLowerCase(searchString.charAt(0))) {
151  continue;
152  }
153 
154  if (damerauLevenshteinDistance(searchString, trimmedTopic.substring(0, searchString.length())) < maxDistance) {
155  possibleMatches.add(topic);
156  }
157  }
158 
159  if (possibleMatches.size() > 0) {
160  return new IndexHelpTopic("Search", null, null, possibleMatches, "Search for: " + searchString);
161  } else {
162  return null;
163  }
164  }
165 
166  /**
167  * Computes the Dameraur-Levenshtein Distance between two strings. Adapted
168  * from the algorithm at <a href="http://en.wikipedia.org/wiki/Damerau–Levenshtein_distance">Wikipedia: Damerau–Levenshtein distance</a>
169  *
170  * @param s1 The first string being compared.
171  * @param s2 The second string being compared.
172  * @return The number of substitutions, deletions, insertions, and
173  * transpositions required to get from s1 to s2.
174  */
175  protected static int damerauLevenshteinDistance(String s1, String s2) {
176  if (s1 == null && s2 == null) {
177  return 0;
178  }
179  if (s1 != null && s2 == null) {
180  return s1.length();
181  }
182  if (s1 == null && s2 != null) {
183  return s2.length();
184  }
185 
186  int s1Len = s1.length();
187  int s2Len = s2.length();
188  int[][] H = new int[s1Len + 2][s2Len + 2];
189 
190  int INF = s1Len + s2Len;
191  H[0][0] = INF;
192  for (int i = 0; i <= s1Len; i++) {
193  H[i + 1][1] = i;
194  H[i + 1][0] = INF;
195  }
196  for (int j = 0; j <= s2Len; j++) {
197  H[1][j + 1] = j;
198  H[0][j + 1] = INF;
199  }
200 
201  Map<Character, Integer> sd = new HashMap<Character, Integer>();
202  for (char Letter : (s1 + s2).toCharArray()) {
203  if (!sd.containsKey(Letter)) {
204  sd.put(Letter, 0);
205  }
206  }
207 
208  for (int i = 1; i <= s1Len; i++) {
209  int DB = 0;
210  for (int j = 1; j <= s2Len; j++) {
211  int i1 = sd.get(s2.charAt(j - 1));
212  int j1 = DB;
213 
214  if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
215  H[i + 1][j + 1] = H[i][j];
216  DB = j;
217  } else {
218  H[i + 1][j + 1] = Math.min(H[i][j], Math.min(H[i + 1][j], H[i][j + 1])) + 1;
219  }
220 
221  H[i + 1][j + 1] = Math.min(H[i + 1][j + 1], H[i1][j1] + (i - i1 - 1) + 1 + (j - j1 - 1));
222  }
223  sd.put(s1.charAt(i - 1), i);
224  }
225 
226  return H[s1Len + 1][s2Len + 1];
227  }
228 }
boolean testPermission(CommandSender target)
Collection< HelpTopic > getHelpTopics()
Command setAliases(List< String > aliases)
HelpTopic getHelpTopic(String topicName)
String getFullText(CommandSender forWho)
Definition: HelpTopic.java:80
void sendMessage(String message)
static ChatPage paginate(String unpaginatedString, int pageNumber)
void setPermission(String permission)
static Server getServer()
Definition: Bukkit.java:50
HelpMap getHelpMap()
static int damerauLevenshteinDistance(String s1, String s2)
abstract boolean canSee(CommandSender player)