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