Giter VIP home page Giter VIP logo

cli's Introduction

C/C++ CI of Cli CodeQL

cli

A cross-platform header only C++14 library for interactive command line interfaces (Cisco style)

demo_local_session

demo_telnet_session

C/C++ CI of Cli

❤️ Sponsor

IMPORTANT: Breaking API changes! Version 2.0 of cli has made breaking changes in order to add more functionality. To migrate your application to new cli version, see the section "Async programming and Schedulers" of this file, or the examples that come with the library.

Features

  • Header only
  • Cross-platform (linux and windows)
  • Menus and submenus
  • Remote sessions (telnet)
  • Persistent history (navigation with arrow keys)
  • Autocompletion (with TAB key)
  • Async interface
  • Colors

How to get CLI library

Dependencies

The library has no dependencies if you don't need remote sessions.

The library depends on asio (either the standalone version or the boost version) only to provide telnet server (i.e., remote sessions).

Installation

The library is header-only: it consists entirely of header files containing templates and inline functions, and requires no separately-compiled library binaries or special treatment when linking.

Extract the archive wherever you want.

Now you must only remember to specify the cli (and optionally asio or boost) paths when compiling your source code.

If you fancy it, a Cmake script is provided. To install you can use:

mkdir build && cd build
cmake ..
sudo make install

or, if you want to specify the installation path:

mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=<cli_install_location>
make install

Alternatively, you can use CMake's FetchContent module to include CLI library in your project directly. Add something like this in your CMakeLists.txt file:

include(FetchContent)
FetchContent_Declare(
  cli
  GIT_REPOSITORY https://github.com/daniele77/cli.git
  GIT_TAG v2.1.0
)
FetchContent_MakeAvailable(cli)

add_executable(main-project)
target_link_libraries(main-project PRIVATE cli::cli)

Compilation of the examples

You can find some examples in the directory "examples". Each .cpp file corresponds to an executable. Each example can be compiled by including cli (and optionally asio/boost header files) and linking pthread on linux (and optionally boost system).

To compile the examples using cmake, use:

mkdir build && cd build

# compile only the examples that do not require boost/asio libraries
cmake .. -DCLI_BuildExamples=ON

# compile the examples by using boost asio libraries
cmake .. -DCLI_BuildExamples=ON -DCLI_UseBoostAsio=ON
# or: cmake .. -DCLI_BuildExamples=ON -DCLI_UseBoostAsio=ON -DBOOST_ROOT=<boost_path>

# compile the examples by using standalone asio library
cmake .. -DCLI_BuildExamples=ON -DCLI_UseStandaloneAsio=ON
# or: cmake .. -DCLI_BuildExamples=ON -DCLI_UseStandaloneAsio=ON -DASIO_INCLUDEDIR=<asio_path>

cmake --build .

In the same directory you can also find:

  • GNU make files (Makefile.noasio, Makefile.boostasio, Makefile.standaloneasio)
  • Windows nmake files (makefile.noasio.win, makefile.boostasio.win, makefile.standaloneasio.win)
  • a Visual Studio solution

If needed, you can specify asio library path in the following ways:

GNU Make

for boost:

make CXXFLAGS="-isystem <boost_include>" LDFLAGS="-L<boost_lib>"

example:

make CXXFLAGS="-isystem /opt/boost_1_66_0/install/x86/include" LDFLAGS="-L/opt/boost_1_66_0/install/x86/lib"

for standalone asio:

make CXXFLAGS="-isystem <asio_include>"

example:

make CXXFLAGS="-isystem /opt/asio-1.18.0/include"

(if you want to use clang instead of gcc, you can set the variable CXX=clang++)

Windows nmake

Optionally set the environment variable ASIO or BOOST to provide the library path. Then, from a visual studio console, start nmake passing one of the makefile.*.win files.

E.g., from a visual studio console, use one of the following commands:

# only compile examples that do not require asio
nmake /f makefile.noasio.win
# compile examples using boost asio
set BOOST=<path of boost libraries>
nmake /f makefile.boostasio.win
# compile examples using standalone asio
set ASIO=<path of asio library>
nmake /f makefile.standaloneasio.win

Visual Studio solution

Currently, the VS solution compiles the examples only with the BOOST dependency.

Set the environment variable BOOST. Then, open the file cli/examples/examples.sln

Compilation of the Doxygen documentation

If you have doxygen installed on your system, you can get the html documentation of the library in this way:

cd doc/doxy
doxygen Doxyfile

CLI usage

At the start of your application, the CLI presents a prompt with the name you provided in the Cli constructor. This indicates you're in the root menu.

Navigation

  • Enter a submenu: Type the submenu name to enter it. The prompt will change to reflect the current submenu.
  • Go back to parent menu: Type the name of the parent menu or .. to return.
  • Navigate history: Use up and down arrow keys to navigate through previously entered commands.
  • Exit: Type exit to terminate the CLI application.

Commands in any menu

  • help: Prints a list of available commands with descriptions.
  • Command execution:
    • Current menu: Enter the name of a command available in the current menu to execute it.
    • Submenu (full path): Specify the complete path (separated by spaces) to a command within a submenu to execute it.

Autocompletion

Use the Tab key to get suggestions for completing command or menu names as you type.

Screen Clearing

Press Ctrl-L to clear the screen at any time.

Parameter parsing

The CLI interpreter can handle sentences using single quotes (') and double quotes ("). Any character (including spaces) enclosed within quotes is considered a single parameter for a command. You can use quotes within parameters by escaping them with a backslash (\).

Examples:

cli> echo "this is a single parameter"
this is a single parameter
cli> echo 'this too is a single parameter'
this too is a single parameter
cli> echo "you can use 'single quotes' inside double quoted parameters"
you can use 'single quotes' inside double quoted parameters
cli> echo 'you can use "double quotes" inside single quoted parameters'
you can use "double quotes" inside single quoted parameters
cli> echo "you can escape \"quotes\" inside a parameter"               
you can escape "quotes" inside a parameter
cli> echo 'you can escape \'single quotes\' inside a parameter'
you can escape 'single quotes' inside a parameter
cli> echo "you can also show backslash \\ ... "                
you can also show backslash \ ... 

Async programming and Schedulers

cli is an asynchronous library, and the handlers of commands are executed by a scheduler, in a thread provided by the user (possibly the main thread), this allows you to develop a single thread application without need to worry about synchronization.

So, your application must have a scheduler and pass it to CliLocalTerminalSession.

The library provides three schedulers:

  • LoopScheduler
  • BoostAsioScheduler
  • StandaloneAsioScheduler

LoopScheduler is the simplest: it does not depend on other libraries and should be your first choice if you don't need remote sessions.

BoostAsioScheduler and StandaloneAsioScheduler are wrappers around asio io_context objects. You should use one of them if you need a BoostAsioCliTelnetServer or a StandaloneAsioCliTelnetServer because they internally use boost::asio and asio.

You should use one of them also if your application uses asio in some way.

After setting up your application, you must call Scheduler::Run() to enter the scheduler loop. Each command handler of the library will execute in the thread that called Scheduler::Run().

You can exit the scheduler loop by calling Scheduler::Stop() (e.g., as an action associated to the "exit" command).

You can submit work to be executed by the scheduler invoking the method Scheduler::Post(const std::function<void()>& f). Schedulers are thread safe, so that you can post function object from any thread, to be executed in the scheduler thread.

This is an example of use of LoopScheduler:

...
LoopScheduler scheduler;
CliLocalTerminalSession localSession(cli, scheduler);
...
// in another thread you can do:
scheduler.Post([](){ cout << "This will be executed in the scheduler thread\n"; });
...
// start the scheduler main loop
// it will exit from this method only when scheduler.Stop() is called
// each cli callback will be executed in this thread
scheduler.Run();
...

This is an example of use of BoostAsioScheduler

...
BoostAsioScheduler scheduler;
CliLocalTerminalSession localSession(cli, scheduler);
BoostAsioCliTelnetServer server(cli, scheduler, 5000);
...
scheduler.Run();
...

Finally, this is an example of use of BoostAsioScheduler when your application already uses boost::asio and has a boost::asio::io_context object (the case of standalone asio is similar).

...
// somewhere else in your application
boost::asio::io_context ioc;
...
// cli setup
BoostAsioScheduler scheduler(ioc);
CliLocalTerminalSession localSession(cli, scheduler);
BoostAsioCliTelnetServer server(cli, scheduler, 5000);
...
// somewhere else in your application
ioc.run();
...

Adding menus and commands

You must provide at least a root menu for your cli:

// create a menu (this is the root menu of our cli)
auto rootMenu = make_unique<Menu>("myprompt");

... // fills rootMenu with commands

// create the cli with the root menu
Cli cli(std::move(rootMenu));

You can add menus to existing menus, to get a hierarchy:

auto rootMenu = make_unique<Menu>("myprompt");
auto menuA = make_unique<Menu>("a_prompt");
auto menuAA = make_unique<Menu>("aa_prompt");
auto menuAB = make_unique<Menu>("ab_prompt");
auto menuAC = make_unique<Menu>("ac_prompt");
auto menuACA = make_unique<Menu>("aca_prompt");
auto menuB = make_unique<Menu>("b_prompt");
auto menuBA = make_unique<Menu>("ba_prompt");
auto menuBB = make_unique<Menu>("bb_prompt");

menuAC->Insert( std::move(menuACA) );
menuB->Insert( std::move(menuBA) );
menuB->Insert( std::move(menuBB) );
menuA->Insert( std::move(menuAA) );
menuA->Insert( std::move(menuAB) );
menuA->Insert( std::move(menuAC) );
rootMenu->Insert( std::move(menuA) );
rootMenu->Insert( std::move(menuB) );

This results in this tree:

myprompt
    |
    +--- a_prompt
    |        |
    |        +--- aa_prompt
    |        |
    |        +--- ab_prompt
    |        |
    |        +--- ac_prompt
    |                |
    |                +--- aca_prompt
    |
    +--- b_prompt
             |
             +--- ba_prompt
             |
             +--- bb_prompt

Finally, you can add commands to menus, using the Menu::Insert method. The library supports adding commands handler via:

  • free functions
  • std::function
  • lambdas
static void foo(std::ostream& out, int x) { out << x << std::endl; }

std::function<void(std::ostream& out, int x)> fun(foo);

...

myMenu->Insert("free_function", foo);

myMenu->Insert("std_function", fun);

myMenu->Insert("lambda", [](std::ostream& out, int x){ out << x << std::endl; } );

There is no limit to the number of parameters that a command handler can take. They can be basic types and std::strings

myMenu->Insert(
    "mycmd", 
    [](std::ostream& out, int a, double b, const std::string& c, bool d, long e)
    { 
        ...
    } );

myMenu->Insert(
    "complex", 
    [](std::ostream& out, std::complex c)
    { 
        ...
    } );

Or they can be custom types by overloading the std::istream::operator>>:

struct Foo
{
    friend istream & operator >> (istream &in, Foo& p);
    int value;
};

istream & operator >> (istream& in, Foo& p)
{
    in >> p.value;
    return in;
}

myMenu->Insert(
    "foo", 
    [](std::ostream& out, Foo f)
    { 
        ...
    } );

If you need it, you can have a command handlers taking an arbitrary number of std::string parameters:

myMenu->Insert(
    "mycmd", 
    [](std::ostream& out, const std::vector<std::string>& pars)
    { 
        ...
    } );

Please note that in this case your command handler must take only one parameter of type std::vector<std::string>.

Enter and exit actions

You can add an enter action and/or an exit action (for example to print a welcome/goodbye message every time a user opens/closes a session, even a remote one):

Cli cli(std::move(rootMenu));
cli.EnterAction(
    [&enterActionDone](std::ostream& out) { out << "Welcome\n"; });
cli.ExitAction(
    [&enterActionDone](std::ostream& out) { out << "Goodbye\n"; });

Custom Handler for Unknown Commands

You can modify the default behavior of the library for cases where the user enters an unknown command or its parameters do not match:

Cli cli(std::move(rootMenu));
cli.WrongCommandHandler(
    [](std::ostream& out, const std::string& cmd)
    {
        out << "Unknown command or incorrect parameters: "
            << cmd
            << ".\n";
    }
);

Standard Exception Custom Handler

You can handle cases where an exception is thrown inside a command handler by registering a specific handler:

Cli cli(std::move(rootMenu));
cli.StdExceptionHandler(
    [](std::ostream& out, const std::string& cmd, const std::exception& e)
    {
        out << "Exception caught in CLI handler: "
            << e.what()
            << " while handling command: "
            << cmd
            << ".\n";
    }
);

Unicode

cli uses the input and output stream objects provided by the standard library (such as std::cin and std::cout) by default, so currently cli does not have effective support for unicode input and output.

If you want to handle unicode input and output, you need to provide custom i/o unicode aware stream objects derived from std::istream or std::ostream.

For example, you can use boost::nowide as an alternative to implement UTF-8 aware programming in a out-of-box and cross-platform way:

#include <boost/nowide/iostream.hpp> // for boost::nowide::cin and boost::nowide::cout
// other headers...

cli::Cli app{/*init code*/};

// FileSession session{app}; // default

// now, all parameters is in a UTF-8 encoded std::string
// pass boost::nowide::cin and boost::nowide::cout as parameters(FileSession requires std::istream and std::ostream)
FileSession session{app, boost::nowide::cin, boost::nowide::cout};

/*....*/

// you can call this command funtion and get UTF-8 encoded input data (p), just use it.
// boost::noide helps us avoid the trouble
// caused by inconsistent default code page and encoding of the console under different platforms.
void a_command_function(std::ostream& os, std::string const& p) {
 /* implements */
}

Of course, you can also pass stream objects with other capabilities to achieve more customized input and output functions.

License

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

Contact

Please report issues here: http://github.com/daniele77/cli/issues

and questions, feature requests, ideas, anything else here: http://github.com/daniele77/cli/discussions

You can always contact me via twitter at @DPallastrelli


Contributing (We Need Your Help!)

Any feedback from users and stakeholders, even simple questions about how things work or why they were done a certain way, carries value and can be used to improve the library.

Even if you just have questions, asking them in GitHub Discussions provides valuable information that can be used to improve the library - do not hesitate, no question is insignificant or unimportant!

If you or your company uses cli library, please consider becoming a sponsor to keep the project strong and dependable.

cli's People

Contributors

artalus avatar daniele77 avatar dup4 avatar evanmcbroom avatar gryffyn avatar hanyukang avatar illukin avatar jobrud avatar lu-maca avatar m-dhooge avatar marcogmaia avatar paulsubrata55 avatar rob-baily avatar sakshamsharma avatar sdebionne avatar stkw0 avatar tete17 avatar vanwinkeljan avatar vrobles-gee avatar xbreak avatar yunchengliu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cli's Issues

C++14 features

Take advantage of unique_ptr and move.
Remove cxx0x.h header file.

Completion for user-defined arguments

How hard would it be to extend it to allow completion also for arguments?
Let's say, for example, I have an command, that can only be called in the following way to be valid:
set_state RUNNING, set_state WAITING and set_state TERMINATED.
I want to have completion of set_state R to set_state RUNNING in this case.

Dinamically adding and removing commands and menu

It's useful adding and removing commands and submenus during the working session. For example, when loading/unloading a plugin at run-time we should be able to add/remove the related cli commands.

To implement this, maybe we should get rid of std::unique_ptr for commands and menus. We need to return an handle when adding commands/submenus, to remove them at a later time.

Provide unique header file for the library

Consider to provide one header file that contains the others.
It could be useful to have two header file: one for the local session and one for the telnet server (or one for the core and the other for the asio part)

problems when using telnet when server is running as service

Hi,
i am running a gateway fw as a service on an 'bionic-armhf' machine (ubuntu 18.04 TLS).
this service acts as the cli server (like in the 'complete' example).
when trying to telnet, it stuck and takes forever to respond.
when running the gateway fw from bash (not as a service), the telnet works just fine.
any idea?

i might have some clue:
when running the complete example as a service, the cpu usage is ~98%.
when running it from bash, the cpu usage is ~1%.

Odd behavior of history

Given the sequence of (valid) commands:

  • cmd1
  • cmd2
  • cmd3

Using the arrow up key we get the history:

  • cmd3
  • cmd2
  • cmd1

And that's ok. From here, if we use the arrow down key we get:

  • cmd3
  • cmd1
  • cmd2

instead of the right sequence:

  • cmd2
  • cmd3
  • cmd1

Linker error when building examples using cmake in Visual Studio 2019

Hey,

I am trying to build the project in Visual Studio 2019, building it as a CMake project. I get the linker error:

"fatal error LNK1104: cannot open file 'libboost_date_time-vc142-mt-gd-x64-1_70.lib'"

I just dont understand where the dependancy on boosts date_time comes into play. Another curious thing is that it is only building complete.cpp and pluginmanager.cpp that fails. The exe files to filesession.cpp and simplelocalsession.cpp are building correctly without errors. Hope you could shed some light on this issue.

If any other information is needed, please let me know

Boost requirement

Nice work! How much would be needed to remove the boost dependency?

Backspace from remote terminal

It looks like backspace may not be properly handled (at least on Windows with the Windows telnet client). With a debugger I can see '\b' in the strings that are matched to commands or arguments. Backspace is properly echoed though. Might be an issue with the telnet client and its configuration.

Session context in menu items

Is it possible to get some context related to the session in the function defined for the menu? One example would be a menu command to enable / disable debug output but only on that session - it wouldn't affect all sessions connected.

Function keys in examples do not work

Hi.
Keys tab, up, down, left, right, backspace, home, end do not work in examples (asyncsession.cpp, simplesession.cpp).
I delete telnet session from complete.cpp, but the program ended immediately.

Avoid duplicated commands on history

Hello. I would like to ask if there is a way to avoid storing the same command over and over on history. If it is not possible right now, can you please provide some hint on the relevant classes/functions to modify to make it work? I will be willing to add it and send a PR. Thanks.

Allow using wrappers around custom dispatchers

Gist:
My particular use-case requires using a custom event dispatcher that selects on file descriptors. I spent a lot of time trying to make that happen with boost::asio::io_service, and concluded that it can't be done (correct me if I'm wrong).

So I'm proposing something different. Allow passing a custom wrapper type instead of boost::asio::io_service to the CliLocalTerminalSession and other objects. This can be done via a template argument defaulting to io_service, or it can be done by expecting a virtual interface that can be pre-implemented for io_service in a helper header.

I can pick this up myself as well when I get time, if there are no objections to the direction.

Basically what I would like to do in my custom wrapper interface / type is: I would make a pipe file descriptor dirty before actually calling Post on the io_service. In my main thread, the dispatcher would be calling select on the other end of the pipe (another file descriptor). It would then call poll on the io_service.

Duplicate autocompletion

If the same command name is used with different arity, the autocompletion (tab) shows the command duplicated.

Build fails...

Boost Version: 1.70.0
OS: Debian GNU/Linux 9 (stretch) 64-bit / Gnome Version 3.22.2
Error Message:

/home/adem/LibSrc/cli/include/cli/remotecli.h:446:28: error: ‘boost::asio::ip::tcp::socket {aka class boost::asio::basic_stream_socket<boost::asio::ip::tcp>}’ has no member named ‘get_io_service’
         InputDevice(socket.get_io_service()),
                            ^~~~~~~~~~~~~~
examples/CMakeFiles/complete.dir/build.make:62: recipe for target 'examples/CMakeFiles/complete.dir/complete.cpp.o' failed

Bind to specific address

Hello. I really like your library, thanks for it. I'm confident it will get better as more functionalities are added.

I am actually using it on an new project, but I am facing the following issue: I need to bind the telnet server to a single address for security reasons. I was checking the source code, but I think that currently it cann't be controlled when creating a CliTelnetServer instance. It seems to listen in all available interfaces by default, am I right?

https://github.com/daniele77/cli/blob/master/include/cli/server.h#L126

If that's the case, can we add a constructor that will allow the developer to specify the IP address he wants the server to listen to? I am willing to help with this PR.

Thanks.

Assertion in `History::Next()`

Steps to reproduce

  1. Start examples/pluginmanager
  2. Press key-down
cli> pluginmanager: include/cli/history.h:99: std::string cli::detail::History::Next(): Assertion `current < buffer.size()' failed.
Aborted

Wrong colors after CANC or BACKSPACE keypress

When you have the colors on and you edit a line by deleting a character, the part of the string following the edit becomes not colored.
This happens both with CANC and BACKSPACE keys.

Optionally delimitate string parameters by "

Currently, you cannot use strings with spaces as parameters to commands. It would be useful to use the symbol " to optionally delimitate a string argument.

Of course, it should be provided an escape mechanism also.

Feed the cli with user strings

Restore the possibility to feed the cli directly with user strings (without the special key handling) and check that AsyncInput class is still working.

Add colored output

Consider to differentiate the prompt, the output and the input with colors.

Colors should be optional and customizable, possibly using a policy (template)

User-defined arguments

The library currently supports only arguments of type:

  • char
  • unsigned char
  • short
  • unsigned short
  • int
  • unsigned int
  • long
  • unsigned long
  • float
  • double
  • long double
  • bool
  • std::string
  • std::vector<std::string>

However, I see two big improvements:

  1. restrict to a subset of values of a type (e.g., an int variable that can only assume the values: {-1000, 0, 1000} or a std::string that can only assume the values: {"red", "green", "blue"}).
  2. use a custom type (e.g., a struct or a class).

See also #157

Add a global output stream

When you register a callback for a command, you get an output stream to provide output on the terminal you gave the command.

It would be useful to provide a "global" output stream (e.g., on the Cli class) to output "broadcast" messages on all the sessions (including remotes one).

Be careful that the global output can be asyncronous, and this could interfere with colors and autocompletion.

Add history of the commands

Memorize in a circular queue the commands with valid syntax.
Add an optional command to show the history.

Default input handler without specifying a command

Like the switch grammar, how about register a default handler for input?
For example: just input three integers after the prompt, and then call the Add command by default.

cli> 1 2 3
6
cli>

It would be nice when a single command is massively used.

BTW, cli now supports Insert a command name of std::string(""), but it seems this command would never be called.

assyncsession not supported on Windows

(and any other non-posix OS) Due to this line
https://github.com/daniele77/cli/blob/master/cli/cliasyncsession.h#L90

Could possibly give a diagnostic?

#if _WIN32
#error "Currently not supported. #issue"
#endif
//or
#if !__has_include(<unistd.h>)
#error "Currently not supported. #issue"
#endif

Of the compilers on Godbolt that support C++14 but not __has_include are gcc 4.9.0 and 4.9.1
Edit: 🤦‍♂️ just realised that Boost has several macros to be able to test for this...

Authentication feature

Hi @daniele77.

Do you believe it would be easy to add authentication to the library?. I know the scope of such a feature can be huge (for instance, supporting multiple authentication mechanisms, supporting multiple users, supporting different set of commands based on permissions and so on), but we could start with a simple scope, something easy like storing a local credentials file (like htpasswd).

My main concern is that right now any APP using the telnet server is open to the public, and the only way to restrict access is protecting it with networking workarounds like firewall rules. What do you think?

Thanks,

Correct visualization of non english keys

In Linux (and with putty as a telnet client on windows), some keyboard keys don't work (àèéùò"£).

In windows, the arrows in the numeric pad don't work.

Linked to this problem, is the backspace that after non-English keys misbehave.

In particular (x = doesn't work):

                                  nocolor                       color
                      special char    backspace     special char    backspace
win local       
win telnet client       
win putty client                                        X
linux locale               X                            X
linux telnet                            X               X

Please note that the problem with non-English keys is only in the local echo of the characters because the cli engine receive the correct input string instead.

Putty on windows should be configured as following:

terminal -> Local echo: "Force off"
terminal -> Local line editing: "Force off"

Customizable messages

Currently, every library message printed to the user (eg help, errors, ...) is in english.
It would be nice to let the user to (optionally) specify those strings at library initialization.

Autocompletion not working

Hello.

I am facing issues with autocompletion. I noticed it works as expected when using a telnet session, but I tested all the other ones (local, file, async) and everytime I try to autocomplete, only the tab is printed as any other character, and the cli gets messed up.

I thought I was doing something wrong, but I tested the examples (generated following the README.md instructions) and experienced the same behavior. I also tested both latest master and v1.1.0 tags.

I am testing using Ubuntu 18.04. Boost version is 1.68. I observe the same behavior in regular terminal as inside vscode terminal. I this a bug, or I am doing something wrong?

Thanks in advance

Problems with putty and accented characters

Using putty terminal with the following settings:
terminal -> Local echo: "Force off"
terminal -> Local line editing: "Force off"
after enabling terminal color (e.g., with the command color in the complete example), some characters ('ò', 'à', 'è', 'é', 'ù', '£') are not echoed correctly on the screen.

Instead, backspace key does not work correctly when the characters 'ò', 'à', 'è', 'é', 'ù', '£' are echoed correctly: the backspace keeps erasing characters even after the start of the prompt...

Telnet server echo

Running the server on either Windows or Linux, I can't make the server echo the commands (or the autocompletion). Is this something that is not impelemented yet? A quick grep on the codebase finds a void TelnetSession::Echo( char c ) that is commented.

TAB autocompletion when many results with same prefix

When you have many results of autocompletion that have the same prefix, pressing the tab key should autocomplete with the whole common prefix.

E.g.,
commands: hello, hello_everybody available
When you digit "hel" and press the tab key, the cli should autocomplete with "hello" (the common prefix)

Persistent history

It would be useful to (optionally) make persistent the cli history.

The local session and each remote session should maintain its own history.
But how to identify remote sessions?
According to the client IP address?
Or more simply by providing one history for the local session and just one for all the remote sessions? In this case, what happens when more than one client is connected simultaneously?

Maybe we could start by providing persistent history just for the local session.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.