void CLICommand::ShowCommands(int argc, char **argv, po::options_description *visibleDesc, po::options_description *hiddenDesc, ArgumentCompletionCallback globalArgCompletionCallback, bool autocomplete, int autoindex) { boost::mutex::scoped_lock lock(GetRegistryMutex()); typedef std::map<std::vector<String>, CLICommand::Ptr>::value_type CLIKeyValue; std::vector<String> best_match; int arg_begin = 0; CLICommand::Ptr command; BOOST_FOREACH(const CLIKeyValue& kv, GetRegistry()) { const std::vector<String>& vname = kv.first; arg_begin = 0; for (int i = 0, k = 1; i < vname.size() && k < argc; i++, k++) { if (strcmp(argv[k], "--no-stack-rlimit") == 0 || strcmp(argv[k], "--autocomplete") == 0 || strcmp(argv[k], "--scm") == 0) { i--; arg_begin++; continue; } if (autocomplete && i >= autoindex - 1) break; if (vname[i] != argv[k]) break; if (i >= best_match.size()) { best_match.push_back(vname[i]); } if (i == vname.size() - 1) { command = kv.second; break; } } } String aword; if (autocomplete) { if (autoindex < argc) aword = argv[autoindex]; if (autoindex - 1 > best_match.size() && !command) return; } else std::cout << "Supported commands: " << std::endl; BOOST_FOREACH(const CLIKeyValue& kv, GetRegistry()) { const std::vector<String>& vname = kv.first; if (vname.size() < best_match.size() || kv.second->IsHidden()) continue; bool match = true; for (int i = 0; i < best_match.size(); i++) { if (vname[i] != best_match[i]) { match = false; break; } } if (!match) continue; if (autocomplete) { String cname; if (autoindex - 1 < vname.size()) { cname = vname[autoindex - 1]; if (cname.Find(aword) == 0) std::cout << cname << "\n"; } } else std::cout << " * " << boost::algorithm::join(vname, " ") << " (" << kv.second->GetShortDescription() << ")" << std::endl; } if (!autocomplete) std::cout << std::endl; if (command && autocomplete) { String aname, prefix, pword; const po::option_description *odesc; if (autoindex - 2 >= 0 && strcmp(argv[autoindex - 1], "=") == 0 && strstr(argv[autoindex - 2], "--") == argv[autoindex - 2]) { aname = argv[autoindex - 2] + 2; pword = aword; } else if (autoindex - 1 >= 0 && argv[autoindex - 1][0] == '-' && argv[autoindex - 1][1] == '-') { aname = argv[autoindex - 1] + 2; pword = aword; if (pword == "=") pword = ""; } else if (autoindex - 1 >= 0 && argv[autoindex - 1][0] == '-' && argv[autoindex - 1][1] != '-') { aname = argv[autoindex - 1]; pword = aword; if (pword == "=") pword = ""; } else if (aword.GetLength() > 1 && aword[0] == '-' && aword[1] != '-') { aname = aword.SubStr(0, 2); prefix = aname; pword = aword.SubStr(2); } else { goto complete_option; } odesc = visibleDesc->find_nothrow(aname, false); if (!odesc) return; if (odesc->semantic()->min_tokens() == 0) goto complete_option; BOOST_FOREACH(const String& suggestion, globalArgCompletionCallback(odesc->long_name(), pword)) { std::cout << prefix << suggestion << "\n"; } BOOST_FOREACH(const String& suggestion, command->GetArgumentSuggestions(odesc->long_name(), pword)) { std::cout << prefix << suggestion << "\n"; } return; complete_option: BOOST_FOREACH(const boost::shared_ptr<po::option_description>& odesc, visibleDesc->options()) { String cname = "--" + odesc->long_name(); if (cname.Find(aword) == 0) std::cout << cname << "\n"; } BOOST_FOREACH(const String& suggestion, command->GetPositionalSuggestions(aword)) { std::cout << suggestion << "\n"; } }