[英]How to implement cross-platform cscope-like text-based user interface?
[英]Cross platform, Interactive text-based interface with command completion
有谁知道将提供基于文本的交互式界面的C ++库? 我想创建一个应用程序的两个版本; 一个基于控制台的程序,它将执行在命令行上或在控制台上交互式执行的任何操作以及基于GUI的程序(Mac Cocoa和Windows MFC)。 两个版本都将共享一个通用的C ++后端。
对于基于控制台的程序,我希望类似的readline历史能力(我不能使用,因为这个应用程序将是闭源),命令完成(例如Tab激活)。
也许有这样的东西已经可用了吗?
没有特别的顺序,(我没有使用过它们),你应该看看:
如果没有一个你喜欢你的另一种可能性,也许它甚至可能是首选。 将您的后端编写为守护进程,并将前端作为一个愚蠢的程序,通过任何形式的进程间通信与后端进行通信。 然后,您可以使用任何GPLed库为您的前端没有任何问题,因为您可以将前端作为开源发布。 当然,这将暴露前端和后端之间的通信协议,所以你必须确保没关系,当然还有其他人可能觉得有必要对你的前端进行自定义,甚至可能自己创建。 但是假设你的价值无论如何都在后端,这不应该造成特别的问题。 它甚至可能被认为是一个优点,它将允许任何有明智想法的人以新的和意想不到的方式使用您的软件,只会增加您的软件的受欢迎程度。
更新:我没有找到一个令人满意的(跨平台)解决方案的历史/完成选项,所以我暂时忽略了它,但我想用我如何实现一个简单的交互式类来更新这个问题。 这个界面不适合主流用户,但我发现它在实现过程中测试我的代码非常方便。 下面是可能帮助其他人的初始实现(请注意,此代码引用了我尚未发布的方法和类型,因此不会立即编译)
Interact.h:
#ifndef INTERACT_H
#define INTERACT_H
class Interact;
class InteractCommand;
typedef void (Interact::*PF_FUNC)(const InteractCommand &command, const StringVector &args);
struct InteractCommand
{
const char *command;
const char *argDesc;
const char *desc;
PF_FUNC func;
};
class Interact
{
private:
static Log m_log;
static InteractCommand m_commands[];
static unsigned m_numCommands;
bool m_stop;
Database &m_database;
StringVector &m_dirs;
public:
Interact(Database &database, StringVector &dirs);
~Interact();
/**
* Main 'interact' loop.
*
* @return true if the loop exitted normally, else false if an error occurred.
*/
bool interact();
private:
// Functions
#define DEFFUNC(f) void FUNC_##f(const InteractCommand &command, const StringVector &args)
DEFFUNC(database);
DEFFUNC(dirs);
DEFFUNC(exit);
DEFFUNC(help);
#undef DEFFUNC
/**
* Print usage information for the specified command.
*
* @param command The command to print usage for.
*/
static void usage(const InteractCommand &command);
static void describeCommand(string &dest, const InteractCommand &command);
};
#endif // INTERACT_H
Interact.cpp:
#include "Interact.h"
Log Interact::m_log("Interact");
#define IFUNC(f) &Interact::FUNC_##f
InteractCommand Interact::m_commands[] =
{
{ "database", "<file>|close", "Use database <file> or close opened database", IFUNC(database) },
{ "dirs", "dir[,dir...]", "Set the directories to scan", IFUNC(dirs) },
{ "exit", 0, "Exit", IFUNC(exit) },
{ "help", 0, "Print help", IFUNC(help) }
};
#undef IFUNC
unsigned Interact::m_numCommands = sizeof(m_commands) / sizeof(m_commands[0]);
Interact::Interact(MusicDatabase &database, StringVector &dirs) :
m_stop(false),
m_database(database),
m_dirs(dirs)
{
}
Interact::~Interact()
{
}
bool Interact::interact()
{
string line;
StringVector args;
unsigned i;
m_stop = false;
while (!m_stop)
{
args.clear();
cout << "> ";
if (!getline(cin, line) || cin.eof())
break;
else if (cin.fail())
return false;
if (!Util::splitString(line, " ", args) || args.size() == 0)
continue;
for (i = 0; i < m_numCommands; i++)
if (strncasecmp(args[0].c_str(), m_commands[i].command, args[0].length()) == 0)
break;
if (i < m_numCommands)
(this->*m_commands[i].func)(m_commands[i], args);
else
cout << "Unknown command '" << args[0] << "'" << endl;
}
return true;
}
void Interact::FUNC_database(const InteractCommand &command, const StringVector &args)
{
if (args.size() != 2)
{
usage(command);
return;
}
if (args[1] == "close")
{
if (m_database.opened())
m_database.close();
else
cout << "Database is not open" << endl;
}
else
{
if (!m_database.open(args[1]))
{
cout << "Failed to open database" << endl;
}
}
}
void Interact::FUNC_dirs(const InteractCommand &command, const StringVector &args)
{
if (args.size() == 1)
{
usage(command);
return;
}
// TODO
}
void Interact::FUNC_exit(const InteractCommand &command, const StringVector &args)
{
m_stop = true;
}
void Interact::FUNC_help(const InteractCommand &command, const StringVector &/*args*/)
{
string descr;
for (unsigned i = 0; i < m_numCommands; i++)
{
describeCommand(descr, m_commands[i]);
cout << descr << endl;
}
}
void Interact::usage(const InteractCommand &command)
{
string descr;
describeCommand(descr, command);
cout << "usage: " << endl;
cout << descr << endl;
}
void Interact::describeCommand(string &dest, const InteractCommand &command)
{
dest.clear();
string cmdStr = command.command;
if (command.argDesc != 0)
{
cmdStr += " ";
cmdStr += command.argDesc;
}
Util::format(dest, " %-30s%s", cmdStr.c_str(), command.desc);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.