25using std::string_view;
35 , openMSXInfoCommand(*this,
"openmsx_info")
36 , hotKey(reactor.getRTScheduler(), *this, eventDistributor)
37 , settingsConfig(*this, hotKey)
39 , tabCompletionCmd(*this)
41 , platformInfo(getOpenMSXInfoCommand())
42 , versionInfo (getOpenMSXInfoCommand())
43 , romInfoTopic(getOpenMSXInfoCommand())
54 assert(commands.empty());
61 auto it = proxyCommandMap.find(name);
62 if (it ==
end(proxyCommandMap)) {
63 it = proxyCommandMap.emplace_noDuplicateCheck(
64 0, std::make_unique<ProxyCmd>(reactor, name));
71 auto it = proxyCommandMap.find(name);
72 assert(it !=
end(proxyCommandMap));
73 assert(it->first > 0);
76 proxyCommandMap.erase(it);
80GlobalCommandController::ProxySettings::iterator
81GlobalCommandController::findProxySetting(string_view name)
84 [](
auto& v) {
return v.first->getFullName(); });
89 const auto& name =
setting.getBaseNameObj();
90 auto it = findProxySetting(name.getString());
91 if (it ==
end(proxySettings)) {
93 auto proxy = std::make_unique<ProxySetting>(reactor, name);
96 proxySettings.emplace_back(std::move(proxy), 1);
105 auto it = findProxySetting(
setting.getBaseName());
106 assert(it !=
end(proxySettings));
109 if (it->second == 0) {
110 auto& proxy = *it->first;
131 assert(!commands.contains(str));
132 commands.emplace_noDuplicateCheck(str, &command);
138 Command& command, string_view str)
142 assert(commands.contains(str));
143 assert(commands[str] == &command);
152 if (str.starts_with(
"::")) str.remove_prefix(2);
160 if (str.starts_with(
"::")) str.remove_prefix(2);
178static vector<string> split(string_view str,
const char delimiter)
180 vector<string> tokens;
182 enum ParseState {Alpha, BackSlash, Quote};
183 ParseState state = Alpha;
185 for (
auto chr : str) {
188 if (tokens.empty()) {
189 tokens.emplace_back();
191 if (chr == delimiter) {
193 tokens.emplace_back();
195 tokens.back() += chr;
198 }
else if (chr ==
'"') {
204 tokens.back() += chr;
210 tokens.back() += chr;
218static string removeEscaping(
const string& str)
220 enum ParseState {Alpha, BackSlash, Quote};
221 ParseState state = Alpha;
224 for (
auto chr : str) {
229 }
else if (chr ==
'"') {
251static vector<string> removeEscaping(std::span<const string> input,
bool keepLastIfEmpty)
253 vector<string> result;
254 for (
const auto& s : input) {
256 result.push_back(removeEscaping(s));
259 if (keepLastIfEmpty && (input.empty() || input.back().empty())) {
260 result.emplace_back();
265static string escapeChars(
const string& str, string_view chars)
268 for (
auto chr : str) {
269 if (chars.find(chr) != string::npos) {
278static string addEscaping(
const string& str,
bool quote,
bool finished)
280 if (str.empty() && finished) {
283 string result = escapeChars(str,
"$[]");
285 result.insert(result.begin(),
'"');
290 result = escapeChars(result,
" ");
304 return interpreter.
execute(command);
314 "While executing ", script,
": ",
e.getMessage());
327 string_view pre = command.substr(0, last);
328 string_view post = command.substr(last);
331 vector<string> originalTokens = split(post,
' ');
332 if (originalTokens.empty()) {
333 originalTokens.emplace_back();
337 auto tokens = removeEscaping(originalTokens,
true);
338 auto oldNum = tokens.size();
340 auto newNum = tokens.size();
341 bool tokenFinished = oldNum != newNum;
344 string& original = originalTokens.back();
345 string& completed = tokens[oldNum - 1];
346 if (!completed.empty()) {
347 bool quote = !original.empty() && (original[0] ==
'"');
348 original = addEscaping(completed, quote, tokenFinished);
351 assert(newNum == (oldNum + 1));
352 assert(tokens.back().empty());
353 originalTokens.emplace_back();
357 return strCat(pre,
join(originalTokens,
' '));
362 if (tokens.empty()) {
366 if (tokens.size() == 1) {
367 string_view cmd = tokens[0];
368 string_view leadingNs;
370 if (cmd.starts_with(
"::")) {
371 cmd.remove_prefix(2);
375 auto p1 = cmd.rfind(
"::");
376 string_view ns = (p1 == string_view::npos) ? cmd : cmd.substr(0, p1 + 2);
380 vector<string> names2;
381 names2.reserve(names.size());
382 for (string_view n1 : names) {
384 if (n1.starts_with(
"::")) n1.remove_prefix(2);
386 if (!n1.starts_with(ns))
continue;
388 string_view n2 = n1.substr(ns.size());
390 auto p2 = n2.find(
"::");
391 auto n3 = (p2 == string_view::npos) ? n1 : n1.substr(0, ns.size() + p2 + 2);
393 names2.push_back(
strCat(leadingNs,
n3));
397 string_view cmd = tokens.front();
398 if (cmd.starts_with(
"::")) cmd.remove_prefix(2);
401 (*v)->tabCompletion(tokens);
403 TclObject command =
makeTclList(
"openmsx::tabcompletion");
404 command.addListElements(tokens);
406 TclObject list = command.executeCommand(interpreter);
407 bool sensitive =
true;
408 auto begin = list.begin();
409 auto end = list.end();
411 auto it2 =
end; --it2;
413 if (back ==
"false") {
416 }
else if (back ==
"true") {
422 }
catch (CommandException&
e) {
424 "Error while executing tab-completion "
425 "proc: ",
e.getMessage());
434GlobalCommandController::HelpCmd::HelpCmd(GlobalCommandController& controller_)
435 : Command(controller_,
"help")
439void GlobalCommandController::HelpCmd::execute(
440 std::span<const TclObject> tokens, TclObject& result)
442 auto& controller =
OUTER(GlobalCommandController, helpCmd);
443 switch (tokens.size()) {
446 "Use 'help [command]' to get help for a specific command\n"
447 "The following commands exist:\n";
448 auto cmds = concat<string_view>(
450 getInterpreter().execute(
"openmsx::all_command_names_with_help"));
452 return c.find(
"::") != std::string_view::npos; }),
455 for (
auto& line : formatListInColumns(cmds)) {
462 if (
const auto* v =
lookup(controller.commandCompleters, tokens[1].getString())) {
463 result = (*v)->help(tokens.subspan(1));
466 command.addListElements(
view::drop(tokens, 1));
467 result = command.executeCommand(getInterpreter());
474string GlobalCommandController::HelpCmd::help(std::span<const TclObject> )
const
476 return "prints help information for commands\n";
479void GlobalCommandController::HelpCmd::tabCompletion(vector<string>& tokens)
const
481 string front = std::move(tokens.front());
482 tokens.erase(
begin(tokens));
483 auto& controller =
OUTER(GlobalCommandController, helpCmd);
484 controller.tabCompletion(tokens);
485 tokens.insert(
begin(tokens), std::move(front));
491GlobalCommandController::TabCompletionCmd::TabCompletionCmd(
492 GlobalCommandController& controller_)
493 : Command(controller_,
"tabcompletion")
497void GlobalCommandController::TabCompletionCmd::execute(
498 std::span<const TclObject> tokens, TclObject& result)
500 checkNumArgs(tokens, 2,
"commandstring");
502 auto& controller =
OUTER(GlobalCommandController, tabCompletionCmd);
503 result = controller.tabCompletion(tokens[1].getString());
506string GlobalCommandController::TabCompletionCmd::help(std::span<const TclObject> )
const
508 return "!!! This command will change in the future !!!\n"
509 "Tries to completes the given argument as if it were typed in "
510 "the console. This command is only useful to provide "
511 "tabcompletion to external console interfaces.";
517GlobalCommandController::UpdateCmd::UpdateCmd(CommandController& commandController_)
518 : Command(commandController_,
"openmsx_update")
525 for (
auto i :
xrange(updateStr.size())) {
526 if (updateStr[i] == name) {
530 throw CommandException(
"No such update type: ", name.getString());
533CliConnection& GlobalCommandController::UpdateCmd::getConnection()
535 auto& controller =
OUTER(GlobalCommandController, updateCmd);
536 if (
auto* c = controller.getConnection()) {
539 throw CommandException(
"This command only makes sense when "
540 "it's used from an external application.");
543void GlobalCommandController::UpdateCmd::execute(
544 std::span<const TclObject> tokens, TclObject& )
546 checkNumArgs(tokens, 3, Prefix{1},
"enable|disable type");
547 if (tokens[1] ==
"enable") {
548 getConnection().setUpdateEnable(getType(tokens[2]),
true);
549 }
else if (tokens[1] ==
"disable") {
550 getConnection().setUpdateEnable(getType(tokens[2]),
false);
556string GlobalCommandController::UpdateCmd::help(std::span<const TclObject> )
const
558 return "Enable or disable update events for external applications. See doc/openmsx-control-xml.txt.";
561void GlobalCommandController::UpdateCmd::tabCompletion(vector<string>& tokens)
const
563 switch (tokens.size()) {
565 using namespace std::literals;
566 static constexpr std::array ops = {
"enable"sv,
"disable"sv};
567 completeString(tokens, ops);
579GlobalCommandController::PlatformInfo::PlatformInfo(InfoCommand& openMSXInfoCommand_)
580 : InfoTopic(openMSXInfoCommand_,
"platform")
584void GlobalCommandController::PlatformInfo::execute(
585 std::span<const TclObject> , TclObject& result)
const
587 result = TARGET_PLATFORM;
590string GlobalCommandController::PlatformInfo::help(std::span<const TclObject> )
const
592 return "Prints openMSX platform.";
597GlobalCommandController::VersionInfo::VersionInfo(InfoCommand& openMSXInfoCommand_)
598 : InfoTopic(openMSXInfoCommand_,
"version")
602void GlobalCommandController::VersionInfo::execute(
603 std::span<const TclObject> , TclObject& result)
const
608string GlobalCommandController::VersionInfo::help(std::span<const TclObject> )
const
610 return "Prints openMSX version.";
Assign new value to some variable and restore the original value when this object goes out of scope.
int getLast() const
Get Start of the last subcommand.
void printWarning(std::string_view message)
static std::span< const std::string_view, NUM_UPDATES > getUpdateStrings()
static void completeString(std::vector< std::string > &tokens, ITER begin, ITER end, bool caseSensitive=true)
~GlobalCommandControllerBase()
hash_map< std::string, CommandCompleter *, XXHasher > commandCompleters
Interpreter & getInterpreter() override
GlobalCommandController(const GlobalCommandController &)=delete
void registerSetting(Setting &setting) override
TODO.
std::string tabCompletion(std::string_view command)
Complete the given command.
void registerProxyCommand(std::string_view name)
CliComm & getCliComm() override
void unregisterProxyCommand(std::string_view name)
void registerCommand(Command &command, zstring_view str) override
(Un)register a command
void registerCompleter(CommandCompleter &completer, std::string_view str) override
(Un)register a command completer, used to complete build-in Tcl cmds
void registerProxySetting(Setting &setting)
TclObject executeCommand(zstring_view command, CliConnection *connection=nullptr) override
Execute the given command.
void unregisterProxySetting(Setting &setting)
void unregisterSetting(Setting &setting) override
void unregisterCompleter(CommandCompleter &completer, std::string_view str) override
void unregisterCommand(Command &command, std::string_view str) override
bool isComplete(zstring_view command)
Returns true iff the command is complete (all braces, quotes etc.
SettingsManager & getSettingsManager()
void source(const std::string &script)
Executes all defined auto commands.
~GlobalCommandController()
TclObject execute(zstring_view command)
TclObject getCommandNames()
void registerSetting(BaseSetting &variable)
void unregisterCommand(Command &command)
TclParser parse(std::string_view command)
TclObject executeFile(zstring_view filename)
bool isComplete(zstring_view command) const
void unregisterSetting(BaseSetting &variable)
void registerCommand(zstring_view name, Command &command)
Helper class to use files in APIs other than openmsx::File.
const std::string & getFilename() const
Returns path to a local uncompressed version of this file.
Contains the main loop of openMSX.
void unregisterSetting(BaseSetting &setting)
void registerSetting(BaseSetting &setting)
static std::string full()
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
mat3 n3(vec3(1, 0, 3), vec3(4, 5, 6), vec3(7, 8, 9))
const Value * lookup(const hash_map< Key, Value, Hasher, Equal > &map, const Key2 &key)
detail::Joiner< Collection, Separator > join(Collection &&col, Separator &&sep)
This file implemented 3 utility functions:
TclObject makeTclList(Args &&... args)
auto remove_if(ForwardRange &&range, UnaryPredicate pred)
auto find(InputRange &&range, const T &value)
constexpr void sort(RandomAccessRange &&range)
constexpr auto drop(Range &&range, size_t n)
constexpr auto keys(Map &&map)
#define OUTER(type, member)
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
std::string strCat(Ts &&...ts)
void strAppend(std::string &result, Ts &&...ts)
constexpr auto xrange(T e)
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)