lionkor / commandline

A C++ commandline for use in servers and chat software. Provides very simple asynchronous input/output.
MIT License
85 stars 13 forks source link
async cplusplus cpp cpp11 cpp17 cross-platform readline terminal

commandline

Linux Build Windows Build CodeFactor

A cross-platfrom C++11 commandline for use in servers and terminal chat software. Provides very simple asynchronous input/output.

Callback-based i/o supported, as well as history, autocomplete, custom prompts, and more (see features)

Example

#include "commandline.h"

int main() {
    Commandline com;
    while (true) {
        if (com.has_command()) {
            auto command = com.get_command();
            com.write("got command: " + command);
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        com.write("this is a message written with com.write");
    }
}

Result:

main.cpp demo gif

Features

Installation

Vcpkg

For vcpkg users there is a lionkor-commandline port that can be installed via vcpkg install lionkor-commandline or by adding it to dependencies section of your vcpkg.json file.

Building from source

  1. Install cmake and a compiler of your choice (on Windows you want Visual Studio (not Visual Studio Code), on Linux either gcc, clang or some other compiler, and on MacOS clang / "apple clang").
  2. Clone this repository somewhere.
  3. Run cmake . -B bin in the cloned repository, with any options you'd like (e.g. -DCMAKE_BUILD_TYPE=Release for a release build).
  4. Run cmake --build bin --parallel to build the library and tests.

It should have then built the library, which you can link against.

You could also put add_subdirectory(commandline) to your CMakeLists, if you clone the repo in the folder such that commandline is a subfolder to your CMakeLists.txt.

Why not X?

Why not GNU readline?

Because it's GPL licensed, which makes it difficult to integrate into more permissive licensed or closed-source / commercial projects. commandline aims to be usable by anyone, as long as MIT license terms are followed.

Why not curses/ncurses?

They're TUI frameworks, this is much less than a TUI. They're also C, which is less handy for C++ projects.

How to use

  1. Construct a Commandline instance. A prompt can optionally be passed in this constructor, or via set_prompt.
Commandline com;
  1. Query for new commands in a loop - this should usually be your main server loop or something similar.
bool is_running = true;
while (is_running) {
  // check if something was entered
  if (com.has_command()) {
    // grab the command from the queue
    // note: undefined if has_command wasn't checked beforehand
    std::string command = com.get_command();
    if (command == "quit") {
      is_running = false;
    }
  }
}
  1. To write to the commandline, use Commandline::write.
com.write("hello, world!");

How to contribute?

We roughly follow issue-driven development, as of v1.0.0. This means that any change you want to make should first be formulated in an issue. Then, it can be implemented on your own fork, and the issue referenced in the commit (like fix #5). Once PR'd and merged, it will automatically close the issue.

Use the .clang-format and the clang-format tool to format your code before submitting.

How does it work?

To support reading and writing at the same time, it's using VT100 ANSI escape codes. This means that, on windows, you need to enable those for your CMD terminal.

Before a new line is output into stdout, the current input line is cleared, the output line is written, and the input line is rewritten in the line below, positioning the cursor where it was, as if nothing happened. This results in the illusion that the input line is fixed below the output, which is a very natural design.

In most terminals and in Microsoft's CMD.exe (as well as standalone WinAPI console applications), this happens instantly and no visual glitches appear, which makes it very fun and smooth to use.

Used In

Commandline is used in https://github.com/BeamMP/BeamMP-Server!