【问题标题】:Cross platform, Interactive text-based interface with command completion跨平台,基于文本的交互式界面,具有命令完成功能
【发布时间】:2011-01-13 06:57:12
【问题描述】:

有人知道提供基于文本的交互界面的 C++ 库吗?我想创建一个应用程序的两个版本;一个基于控制台的程序,它将执行在命令行上给出的任何操作或在控制台交互地执行任何操作,以及一个基于 GUI 的程序(Mac Cocoa 和 Windows MFC)。两个版本将共享一个通用的 C++ 后端。

对于基于控制台的程序,我希望具有与 readline 类似的历史记录功能(我无法使用,因为此应用程序将是封闭源代码)并具有命令完成功能(例如,Tab 激活)。

也许已经有类似的东西了?

【问题讨论】:

    标签: c++ autocomplete history console-application


    【解决方案1】:

    没有特别的顺序,(我一个都没用过)你应该看看:

    如果这些都不是您喜欢的,那么您还有另一种可能性,也许它甚至可能是首选。把你的后端写成一个守护进程,让前端是一个愚蠢的程序,它通过任何形式的进程间通信与后端通信。然后,您可以毫无问题地将任何 GPL 库用于您的前端,因为您可以将前端作为开源发布。当然,这将暴露前端和后端之间的通信协议,因此您必须确保对此感到满意,当然其他人可能会觉得需要对您的前端进行自定义,甚至可能自己进行自定义。但是假设您的价值无论如何都在后端,这不应该造成特别的问题。它甚至可能被认为是一个加分项,它可以让任何有好主意的人以新的和意想不到的方式使用您的软件,只会增加您的软件的受欢迎程度。

    【讨论】:

    • 非常感谢您的建议。所有这些库仅适用于 UNIX/LINUX,而不适用于不满足跨平台要求的 Windows。目前我已经编写了自己的简单命令解释器并且忽略了历史/命令完成方面。 TBH 这可能足以让我开心一段时间。
    【解决方案2】:

    更新:我还没有找到历史/完成选项的令人满意的(跨平台)解决方案,所以我暂时忽略了这一点,但我想用我如何实现一个更新这个问题简单的互动课堂。这个接口不适用于主流用户,但我发现它在实现过程中测试我的代码非常方便。以下是可能对其他人有所帮助的初始实现(请注意,此代码引用了我尚未发布的方法和类型,因此不会开箱即用)

    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);
    }
    

    【讨论】:

      猜你喜欢
      • 2013-12-23
      • 1970-01-01
      • 1970-01-01
      • 2014-12-01
      • 2017-11-13
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多