Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: tools/gn/command_help.cc

Issue 1681363003: Add spell-checking to `gn help`. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: #$^&*&^$ Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <algorithm> 5 #include <algorithm>
6 #include <iostream> 6 #include <iostream>
7 7
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "tools/gn/args.h" 9 #include "tools/gn/args.h"
10 #include "tools/gn/commands.h" 10 #include "tools/gn/commands.h"
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 bool PrintHelpOnSwitch(const std::string& what) { 136 bool PrintHelpOnSwitch(const std::string& what) {
137 const switches::SwitchInfoMap& all = switches::GetSwitches(); 137 const switches::SwitchInfoMap& all = switches::GetSwitches();
138 switches::SwitchInfoMap::const_iterator found = 138 switches::SwitchInfoMap::const_iterator found =
139 all.find(base::StringPiece(what)); 139 all.find(base::StringPiece(what));
140 if (found == all.end()) 140 if (found == all.end())
141 return false; 141 return false;
142 PrintLongHelp(found->second.long_help); 142 PrintLongHelp(found->second.long_help);
143 return true; 143 return true;
144 } 144 }
145 145
146 size_t EditDistance(const base::StringPiece& s1,
brettw 2016/02/16 20:48:28 This is exciting, I've been wanting to add spellch
147 const base::StringPiece& s2,
148 size_t max_edit_distance) {
149 // The algorithm implemented below is the "classic"
150 // dynamic-programming algorithm for computing the Levenshtein
151 // distance, which is described here:
152 //
153 // http://en.wikipedia.org/wiki/Levenshtein_distance
154 //
155 // Although the algorithm is typically described using an m x n
156 // array, only one row plus one element are used at a time, so this
157 // implementation just keeps one vector for the row. To update one entry,
158 // only the entries to the left, top, and top-left are needed. The left
159 // entry is in row[x-1], the top entry is what's in row[x] from the last
160 // iteration, and the top-left entry is stored in previous.
161 size_t m = s1.size();
162 size_t n = s2.size();
163
164 std::vector<size_t> row(n + 1);
165 for (size_t i = 1; i <= n; ++i)
166 row[i] = i;
167
168 for (size_t y = 1; y <= m; ++y) {
169 row[0] = y;
170 size_t best_this_row = row[0];
171
172 size_t previous = y - 1;
173 for (size_t x = 1; x <= n; ++x) {
174 size_t old_row = row[x];
175 row[x] = std::min(previous + (s1[y - 1] == s2[x - 1] ? 0u : 1u),
176 std::min(row[x - 1], row[x]) + 1u);
177 previous = old_row;
178 best_this_row = std::min(best_this_row, row[x]);
179 }
180
181 if (max_edit_distance && best_this_row > max_edit_distance)
182 return max_edit_distance + 1;
183 }
184
185 return row[n];
186 }
187
188 base::StringPiece SpellcheckString(
189 const std::string& text,
190 const std::vector<base::StringPiece>& words) {
191 const size_t kMaxValidEditDistance = 3u;
192
193 size_t min_distance = kMaxValidEditDistance + 1u;
194 base::StringPiece result;
195 for (base::StringPiece word : words) {
196 size_t distance = EditDistance(word, text, kMaxValidEditDistance);
197 if (distance < min_distance) {
198 min_distance = distance;
199 result = word;
200 }
201 }
202 return result;
203 }
204
146 } // namespace 205 } // namespace
147 206
148 const char kHelp[] = "help"; 207 const char kHelp[] = "help";
149 const char kHelp_HelpShort[] = 208 const char kHelp_HelpShort[] =
150 "help: Does what you think."; 209 "help: Does what you think.";
151 const char kHelp_Help[] = 210 const char kHelp_Help[] =
152 "gn help <anything>\n" 211 "gn help <anything>\n"
153 " Yo dawg, I heard you like help on your help so I put help on the help\n" 212 " Yo dawg, I heard you like help on your help so I put help on the help\n"
154 " in the help.\n"; 213 " in the help.\n";
155 214
(...skipping 13 matching lines...) Expand all
169 // Switch help needs to be done separately. The CommandLine will strip the 228 // Switch help needs to be done separately. The CommandLine will strip the
170 // switch separators so --args will come out as "args" which is then 229 // switch separators so --args will come out as "args" which is then
171 // ambiguous with the variable named "args". 230 // ambiguous with the variable named "args".
172 if (!PrintHelpOnSwitch(switches.begin()->first)) 231 if (!PrintHelpOnSwitch(switches.begin()->first))
173 PrintToplevelHelp(); 232 PrintToplevelHelp();
174 return 0; 233 return 0;
175 } else { 234 } else {
176 what = args[0]; 235 what = args[0];
177 } 236 }
178 237
238 std::vector<base::StringPiece> all_help_topics;
239
179 // Check commands. 240 // Check commands.
180 const commands::CommandInfoMap& command_map = commands::GetCommands(); 241 const commands::CommandInfoMap& command_map = commands::GetCommands();
181 commands::CommandInfoMap::const_iterator found_command = 242 auto found_command = command_map.find(what);
182 command_map.find(what);
183 if (found_command != command_map.end()) { 243 if (found_command != command_map.end()) {
184 PrintLongHelp(found_command->second.help); 244 PrintLongHelp(found_command->second.help);
185 return 0; 245 return 0;
186 } 246 }
247 for (const auto& entry : command_map)
248 all_help_topics.push_back(entry.first);
187 249
188 // Check functions. 250 // Check functions.
189 const functions::FunctionInfoMap& function_map = functions::GetFunctions(); 251 const functions::FunctionInfoMap& function_map = functions::GetFunctions();
190 functions::FunctionInfoMap::const_iterator found_function = 252 auto found_function = function_map.find(what);
191 function_map.find(what);
192 if (found_function != function_map.end()) { 253 if (found_function != function_map.end()) {
193 PrintLongHelp(found_function->second.help); 254 PrintLongHelp(found_function->second.help);
194 return 0; 255 return 0;
195 } 256 }
257 for (const auto& entry : function_map)
258 all_help_topics.push_back(entry.first);
196 259
197 // Builtin variables. 260 // Builtin variables.
198 const variables::VariableInfoMap& builtin_vars = 261 const variables::VariableInfoMap& builtin_vars =
199 variables::GetBuiltinVariables(); 262 variables::GetBuiltinVariables();
200 variables::VariableInfoMap::const_iterator found_builtin_var = 263 auto found_builtin_var = builtin_vars.find(what);
201 builtin_vars.find(what);
202 if (found_builtin_var != builtin_vars.end()) { 264 if (found_builtin_var != builtin_vars.end()) {
203 PrintLongHelp(found_builtin_var->second.help); 265 PrintLongHelp(found_builtin_var->second.help);
204 return 0; 266 return 0;
205 } 267 }
268 for (const auto& entry : builtin_vars)
269 all_help_topics.push_back(entry.first);
206 270
207 // Target variables. 271 // Target variables.
208 const variables::VariableInfoMap& target_vars = 272 const variables::VariableInfoMap& target_vars =
209 variables::GetTargetVariables(); 273 variables::GetTargetVariables();
210 variables::VariableInfoMap::const_iterator found_target_var = 274 auto found_target_var = target_vars.find(what);
211 target_vars.find(what);
212 if (found_target_var != target_vars.end()) { 275 if (found_target_var != target_vars.end()) {
213 PrintLongHelp(found_target_var->second.help); 276 PrintLongHelp(found_target_var->second.help);
214 return 0; 277 return 0;
215 } 278 }
279 for (const auto& entry : target_vars)
280 all_help_topics.push_back(entry.first);
216 281
217 // Random other topics. 282 // Random other topics.
218 if (what == "all") { 283 std::map<std::string, std::function<void()>> random_topics;
219 PrintAllHelp(); 284 random_topics["all"] = PrintAllHelp;
285 random_topics["buildargs"] = [=]() { PrintLongHelp(kBuildArgs_Help); };
286 random_topics["dotfile"] = [=]() { PrintLongHelp(kDotfile_Help); };
287 random_topics["grammar"] = [=]() { PrintLongHelp(kGrammar_Help); };
288 random_topics["input_conversion"] = [=]() {
289 PrintLongHelp(kInputConversion_Help);
290 };
291 random_topics["label_pattern"] = [=]() { PrintLongHelp(kLabelPattern_Help); };
292 random_topics["runtime_deps"] = [=]() { PrintLongHelp(kRuntimeDeps_Help); };
293 random_topics["source_expansion"] = [=]() {
294 PrintLongHelp(kSourceExpansion_Help);
295 };
296 random_topics["switches"] = PrintSwitchHelp;
297 auto found_random_topic = random_topics.find(what);
298 if (found_random_topic != random_topics.end()) {
299 found_random_topic->second();
220 return 0; 300 return 0;
221 } 301 }
222 if (what == "buildargs") { 302 for (const auto& entry : random_topics)
223 PrintLongHelp(kBuildArgs_Help); 303 all_help_topics.push_back(entry.first);
224 return 0;
225 }
226 if (what == "dotfile") {
227 PrintLongHelp(kDotfile_Help);
228 return 0;
229 }
230 if (what == "grammar") {
231 PrintLongHelp(kGrammar_Help);
232 return 0;
233 }
234 if (what == "input_conversion") {
235 PrintLongHelp(kInputConversion_Help);
236 return 0;
237 }
238 if (what == "label_pattern") {
239 PrintLongHelp(kLabelPattern_Help);
240 return 0;
241 }
242 if (what == "runtime_deps") {
243 PrintLongHelp(kRuntimeDeps_Help);
244 return 0;
245 }
246 if (what == "source_expansion") {
247 PrintLongHelp(kSourceExpansion_Help);
248 return 0;
249 }
250 if (what == "switches") {
251 PrintSwitchHelp();
252 return 0;
253 }
254 304
255 // No help on this. 305 // No help on this.
256 Err(Location(), "No help on \"" + what + "\".").PrintToStdout(); 306 Err(Location(), "No help on \"" + what + "\".").PrintToStdout();
257 RunHelp(std::vector<std::string>()); 307 base::StringPiece suggestion = SpellcheckString(what, all_help_topics);
308 if (suggestion.empty()) {
309 OutputString("Run `gn help` for a list of available topics.\n",
310 DECORATION_NONE);
311 } else {
312 OutputString("Did you mean `gn help " + suggestion.as_string() + "`?\n",
313 DECORATION_NONE);
314 }
258 return 1; 315 return 1;
259 } 316 }
260 317
261 } // namespace commands 318 } // namespace commands
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698