25 using std::string_view;
36 , openMSXInfoCommand(*this,
"openmsx_info")
37 , hotKey(reactor.getRTScheduler(), *this, eventDistributor)
38 , settingsConfig(*this, hotKey)
40 , tabCompletionCmd(*this)
42 , platformInfo(getOpenMSXInfoCommand())
43 , versionInfo (getOpenMSXInfoCommand())
44 , romInfoTopic(getOpenMSXInfoCommand())
55 assert(commands.empty());
62 auto it = proxyCommandMap.find(name);
63 if (it ==
end(proxyCommandMap)) {
64 it = proxyCommandMap.emplace_noDuplicateCheck(
65 0, std::make_unique<ProxyCmd>(reactor, name));
72 auto it = proxyCommandMap.find(name);
73 assert(it !=
end(proxyCommandMap));
74 assert(it->first > 0);
77 proxyCommandMap.erase(it);
81 GlobalCommandController::ProxySettings::iterator
82 GlobalCommandController::findProxySetting(string_view name)
85 [](
auto& v) {
return v.first->getFullName(); });
90 const auto& name =
setting.getBaseNameObj();
91 auto it = findProxySetting(name.getString());
92 if (it ==
end(proxySettings)) {
94 auto proxy = std::make_unique<ProxySetting>(reactor, name);
97 proxySettings.emplace_back(std::move(proxy), 1);
106 auto it = findProxySetting(
setting.getBaseName());
107 assert(it !=
end(proxySettings));
110 if (it->second == 0) {
111 auto& proxy = *it->first;
132 assert(!commands.contains(str));
133 commands.emplace_noDuplicateCheck(str, &command);
139 Command& command, string_view str)
143 assert(commands.contains(str));
144 assert(commands[str] == &command);
153 if (str.starts_with(
"::")) str.remove_prefix(2);
161 if (str.starts_with(
"::")) str.remove_prefix(2);
179 static vector<string> split(string_view str,
const char delimiter)
181 vector<string> tokens;
183 enum ParseState {Alpha, BackSlash, Quote};
184 ParseState state = Alpha;
186 for (
auto chr : str) {
189 if (tokens.empty()) {
190 tokens.emplace_back();
192 if (chr == delimiter) {
194 tokens.emplace_back();
196 tokens.back() += chr;
199 }
else if (chr ==
'"') {
205 tokens.back() += chr;
211 tokens.back() += chr;
219 static string removeEscaping(
const string& str)
221 enum ParseState {Alpha, BackSlash, Quote};
222 ParseState state = Alpha;
225 for (
auto chr : str) {
230 }
else if (chr ==
'"') {
252 static vector<string> removeEscaping(std::span<const string> input,
bool keepLastIfEmpty)
254 vector<string> result;
255 for (
const auto& s : input) {
257 result.push_back(removeEscaping(s));
260 if (keepLastIfEmpty && (input.empty() || input.back().empty())) {
261 result.emplace_back();
266 static string escapeChars(
const string& str, string_view chars)
269 for (
auto chr : str) {
270 if (chars.find(chr) != string::npos) {
279 static string addEscaping(
const string& str,
bool quote,
bool finished)
281 if (str.empty() && finished) {
284 string result = escapeChars(str,
"$[]");
286 result.insert(result.begin(),
'"');
291 result = escapeChars(result,
" ");
305 return interpreter.
execute(command);
315 "While executing ", script,
": ",
e.getMessage());
328 string_view pre = command.substr(0, last);
329 string_view post = command.substr(last);
332 vector<string> originalTokens = split(post,
' ');
333 if (originalTokens.empty()) {
334 originalTokens.emplace_back();
338 auto tokens = removeEscaping(originalTokens,
true);
339 auto oldNum = tokens.size();
341 auto newNum = tokens.size();
342 bool tokenFinished = oldNum != newNum;
345 string& original = originalTokens.back();
346 string& completed = tokens[oldNum - 1];
347 if (!completed.empty()) {
348 bool quote = !original.empty() && (original[0] ==
'"');
349 original = addEscaping(completed, quote, tokenFinished);
352 assert(newNum == (oldNum + 1));
353 assert(tokens.back().empty());
354 originalTokens.emplace_back();
358 return strCat(pre,
join(originalTokens,
' '));
363 if (tokens.empty()) {
367 if (tokens.size() == 1) {
368 string_view cmd = tokens[0];
369 string_view leadingNs;
371 if (cmd.starts_with(
"::")) {
372 cmd.remove_prefix(2);
376 auto p1 = cmd.rfind(
"::");
377 string_view ns = (p1 == string_view::npos) ? cmd : cmd.substr(0, p1 + 2);
381 vector<string> names2;
382 names2.reserve(names.size());
383 for (string_view n1 : names) {
385 if (n1.starts_with(
"::")) n1.remove_prefix(2);
387 if (!n1.starts_with(ns))
continue;
389 string_view n2 = n1.substr(ns.size());
391 auto p2 = n2.find(
"::");
392 auto n3 = (p2 == string_view::npos) ? n1 : n1.substr(0, ns.size() + p2 + 2);
394 names2.push_back(
strCat(leadingNs,
n3));
398 string_view cmd = tokens.front();
399 if (cmd.starts_with(
"::")) cmd.remove_prefix(2);
402 (*v)->tabCompletion(tokens);
404 TclObject command =
makeTclList(
"openmsx::tabcompletion");
405 command.addListElements(tokens);
407 TclObject list = command.executeCommand(interpreter);
408 bool sensitive =
true;
409 auto begin = list.begin();
410 auto end = list.end();
412 auto it2 =
end; --it2;
414 if (back ==
"false") {
417 }
else if (back ==
"true") {
423 }
catch (CommandException&
e) {
425 "Error while executing tab-completion "
426 "proc: ",
e.getMessage());
435 GlobalCommandController::HelpCmd::HelpCmd(GlobalCommandController& controller_)
436 : Command(controller_,
"help")
440 void GlobalCommandController::HelpCmd::execute(
441 std::span<const TclObject> tokens, TclObject& result)
443 auto& controller =
OUTER(GlobalCommandController, helpCmd);
444 switch (tokens.size()) {
447 "Use 'help [command]' to get help for a specific command\n"
448 "The following commands exist:\n";
449 auto cmds = concat<string_view>(
451 getInterpreter().execute(
"openmsx::all_command_names_with_help"));
453 return c.find(
"::") != std::string_view::npos; }),
456 for (
auto& line : formatListInColumns(cmds)) {
463 if (
const auto* v =
lookup(controller.commandCompleters, tokens[1].getString())) {
464 result = (*v)->help(tokens.subspan(1));
467 command.addListElements(
view::drop(tokens, 1));
468 result = command.executeCommand(getInterpreter());
475 string GlobalCommandController::HelpCmd::help(std::span<const TclObject> )
const
477 return "prints help information for commands\n";
480 void GlobalCommandController::HelpCmd::tabCompletion(vector<string>& tokens)
const
482 string front = std::move(tokens.front());
483 tokens.erase(
begin(tokens));
484 auto& controller =
OUTER(GlobalCommandController, helpCmd);
485 controller.tabCompletion(tokens);
486 tokens.insert(
begin(tokens), std::move(front));
492 GlobalCommandController::TabCompletionCmd::TabCompletionCmd(
493 GlobalCommandController& controller_)
494 : Command(controller_,
"tabcompletion")
498 void GlobalCommandController::TabCompletionCmd::execute(
499 std::span<const TclObject> tokens, TclObject& result)
501 checkNumArgs(tokens, 2,
"commandstring");
503 auto& controller =
OUTER(GlobalCommandController, tabCompletionCmd);
504 result = controller.tabCompletion(tokens[1].getString());
507 string GlobalCommandController::TabCompletionCmd::help(std::span<const TclObject> )
const
509 return "!!! This command will change in the future !!!\n"
510 "Tries to completes the given argument as if it were typed in "
511 "the console. This command is only useful to provide "
512 "tabcompletion to external console interfaces.";
518 GlobalCommandController::UpdateCmd::UpdateCmd(CommandController& commandController_)
519 : Command(commandController_,
"openmsx_update")
526 for (
auto i :
xrange(updateStr.size())) {
527 if (updateStr[i] == name) {
531 throw CommandException(
"No such update type: ", name.getString());
534 CliConnection& GlobalCommandController::UpdateCmd::getConnection()
536 auto& controller =
OUTER(GlobalCommandController, updateCmd);
537 if (
auto* c = controller.getConnection()) {
540 throw CommandException(
"This command only makes sense when "
541 "it's used from an external application.");
544 void GlobalCommandController::UpdateCmd::execute(
545 std::span<const TclObject> tokens, TclObject& )
547 checkNumArgs(tokens, 3, Prefix{1},
"enable|disable type");
548 if (tokens[1] ==
"enable") {
549 getConnection().setUpdateEnable(getType(tokens[2]),
true);
550 }
else if (tokens[1] ==
"disable") {
551 getConnection().setUpdateEnable(getType(tokens[2]),
false);
557 string GlobalCommandController::UpdateCmd::help(std::span<const TclObject> )
const
559 return "Enable or disable update events for external applications. See doc/openmsx-control-xml.txt.";
562 void GlobalCommandController::UpdateCmd::tabCompletion(vector<string>& tokens)
const
564 switch (tokens.size()) {
566 using namespace std::literals;
567 static constexpr std::array ops = {
"enable"sv,
"disable"sv};
568 completeString(tokens, ops);
580 GlobalCommandController::PlatformInfo::PlatformInfo(InfoCommand& openMSXInfoCommand_)
581 : InfoTopic(openMSXInfoCommand_,
"platform")
585 void GlobalCommandController::PlatformInfo::execute(
586 std::span<const TclObject> , TclObject& result)
const
588 result = TARGET_PLATFORM;
591 string GlobalCommandController::PlatformInfo::help(std::span<const TclObject> )
const
593 return "Prints openMSX platform.";
598 GlobalCommandController::VersionInfo::VersionInfo(InfoCommand& openMSXInfoCommand_)
599 : InfoTopic(openMSXInfoCommand_,
"version")
603 void GlobalCommandController::VersionInfo::execute(
604 std::span<const TclObject> , TclObject& result)
const
609 string GlobalCommandController::VersionInfo::help(std::span<const TclObject> )
const
611 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 char *const > 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
SettingsManager & getSettingsManager()
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.
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)