简体   繁体   English

跨平台,基于交互式文本的界面,具有命令完成功能

[英]Cross platform, Interactive text-based interface with command completion

Does anyone know of a C++ library that will provide a text-based interactive interface? 有谁知道将提供基于文本的交互式界面的C ++库? I want to create two versions of an application; 我想创建一个应用程序的两个版本; a console based program that will perform whatever actions are given on the command line or interactively at the console as well as a GUI based program (Mac Cocoa and Windows MFC). 一个基于控制台的程序,它将执行在命令行上或在控制台上交互式执行的任何操作以及基于GUI的程序(Mac Cocoa和Windows MFC)。 Both versions will share a common C++ backend. 两个版本都将共享一个通用的C ++后端。

For the console based program I would like similar history abilities to readline (which I cannot use as this application will be closed source) with command completion (Tab-activated for example). 对于基于控制台的程序,我希望类似的readline历史能力(我不能使用,因为这个应用程序将是闭源),命令完成(例如Tab激活)。

Perhaps there is something like this already available? 也许有这样的东西已经可用了吗?

In no particular order, (I've used none of them,) you should have a look at: 没有特别的顺序,(我没有使用过它们),你应该看看:

If none of those take your fancy you have one other possibility, and perhaps it may even be preferred. 如果没有一个你喜欢你的另一种可能性,也许它甚至可能是首选。 Write your backend as a daemon and have the frontend be a dumb program that communicates with the backend via any form of inter process communication. 将您的后端编写为守护进程,并将前端作为一个愚蠢的程序,通过任何形式的进程间通信与后端进行通信。 You can then use any GPLed library for your frontend without any problem as you can release the frontend as open source. 然后,您可以使用任何GPLed库为您的前端没有任何问题,因为您可以将前端作为开源发布。 Of course this will expose the communication protocol between frontend and backend, so you must be sure to be okay with that and of course the possibility that others may feel the need to make customizations to your frontend and perhaps even make their own. 当然,这将暴露前端和后端之间的通信协议,所以你必须确保没关系,当然还有其他人可能觉得有必要对你的前端进行自定义,甚至可能自己创建。 But assuming that your value is in the backend anyway, this should not pose a particular problem. 但是假设你的价值无论如何都在后端,这不应该造成特别的问题。 And it may even be considered a plus, it would allow anyone with a bright idea to use your software in new and unexpected ways only increasing the popularity of your software. 它甚至可能被认为是一个优点,它将允许任何有明智想法的人以新的和意想不到的方式使用您的软件,只会增加您的软件的受欢迎程度。

Update: I haven't found a satisfactory (cross-platform) solution to the history/completion option, so I've ignored that for the time being, but I wanted to update this question with how I've implemented a simple interactive class. 更新:我没有找到一个令人满意的(跨平台)解决方案的历史/完成选项,所以我暂时忽略了它,但我想用我如何实现一个简单的交互式类来更新这个问题。 This interface won't be for mainstream user's but I'm finding it very handy for testing my code during implementation. 这个界面不适合主流用户,但我发现它在实现过程中测试我的代码非常方便。 Below is the initial implementation that might help others out (note that this code references methods and types I have not published, so won't compile out of the box) 下面是可能帮助其他人的初始实现(请注意,此代码引用了我尚未发布的方法和类型,因此不会立即编译)

Interact.h: 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: 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM