2011-01-13 2 views
5

Кто-нибудь знает библиотеку C++, которая предоставит текстовый интерактивный интерфейс? Я хочу создать две версии приложения; консольная программа, которая будет выполнять любые действия в командной строке или интерактивно на консоли, а также программу на основе графического интерфейса (Mac Cocoa и Windows MFC). Обе версии будут совместно использовать общий C++-сервер.Перекрестная платформа, интерактивный текстовый интерфейс с завершением команды

Для консольной программы я хотел бы, чтобы аналогичные возможности истории были для readline (которые я не могу использовать, так как это приложение будет закрытым исходным кодом) с завершением команды (например, активировано Tab).

Возможно, что-то подобное уже доступно?

ответ

1

Обновление: Я не нашел удовлетворительного (кросс-платформенного) решения опции истории/завершения, поэтому пока что проигнорировал это, но я хотел обновить этот вопрос, как я реализовал простой интерактивный класс. Этот интерфейс не будет использоваться для основного пользователя, но я считаю его очень удобным для тестирования моего кода во время реализации. Ниже приводится первоначальная реализация, которая может помогать другим (обратите внимание, что этот код ссылается на методы и типы я не опубликованы, поэтому не будет компилироваться из коробки)

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 

Взаимодействовать .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); 
} 
2

В произвольном порядке (я не использовали ни один из них), вы должны взглянуть на:

Если ни один из те берут ваше воображение, у вас есть еще одна возможность, и, возможно, это может быть даже предпочтительнее. Напишите свой сервер в качестве демона и убедитесь, что внешний интерфейс является немой программой, которая взаимодействует с бэкэнд посредством любой формы взаимодействия между процессами. Вы можете использовать любую библиотеку GPLed для своего интерфейса без каких-либо проблем, так как вы можете освободить интерфейс в качестве открытого источника. Конечно, это разоблачит протокол связи между интерфейсом и бэкэнд, поэтому вы должны быть уверены в этом, и, конечно, возможность того, что другие могут почувствовать необходимость в настройке вашего интерфейса и, возможно, даже сделать свой собственный. Но, полагая, что ваша ценность в бэкэнде в любом случае, это не должно представлять особой проблемы. И это даже можно считать плюсом, это позволит любому, у кого есть яркая идея, использовать ваше программное обеспечение новыми и неожиданными способами, только увеличивая популярность вашего программного обеспечения.

+0

Большое спасибо за предложения. Все эти библиотеки предназначены только для UNIX/LINUX, а не для Windows, что не соответствует кросс-платформенному требованию. На данный момент я написал собственный простой интерпретатор команд и проигнорировал аспект завершения истории/команды. TBH этого, вероятно, будет достаточно, чтобы я был счастлив некоторое время. – trojanfoe

Смежные вопросы