/ynot

Add some style, advanced cursor movements, and more to your C++ terminal app!

Primary LanguageC++MIT LicenseMIT

ynot

Add color, style, advanced cursor movements, fancy menus, and more to your C++ terminal app! This fully cross-platform library includes a variety of functions and classes to make common challenges easier.

download

You can download this library into your project with git by using git submodule add https://github.com/wheelercj/ynot and then adding #include "../ynot/ynot/ynot.h" (and optionally using namespace ynot;) to the files you want to use this library in. Get future updates with git submodule update --remote. The library's version number is saved in ynot.h so that you can check whether you have the latest version in the future.

Alternatively, you can manually download a zip file or a tar.gz file and go through a similar setup process.

If you're using Visual Studio, each time you download or update the library you will also need to:

  • add any of the library's files you haven't added yet to your project's solution explorer (here's a guide)
  • rescan the solution by right-clicking on your project in the solution explorer and choosing "Rescan Solution"

examples

See the header files for the lists of functions and their descriptions. There are many examples of how you can use this library below, in the test files, in terminal paint, and in the matrix. C++17 or newer is required; in Visual Studio, you can choose the version of C++ with project > Properties > C/C++ > Language > C++ Language Standard.

The ynot library's print function (and other functions that print) allows you to print any emoji or other Unicode symbols to a terminal. On Windows, printing emoji with C++ is normally very complicated. With this print function, it couldn't be more simple.

ynot::print("🔥🐊");
ynot::print("\n I can print anything 😎🤖");

To print emoji, the file must be saved with the UTF-8 encoding (without signature/BOM) and your code must run in a modern terminal (such as Windows Terminal; see how to run your C++ app in Windows Terminal). On Windows, you must use the emoji or Unicode symbol itself in your code rather than a Unicode code point (Unicode code points only work in wstrings).

Here is the get_key function which can instantly detect key presses without an enter key press:

string key = "";
while (key != "escape")
{
    key = ynot::get_key();
    ynot::print("\r                               \r You pressed " + key);
}

get_key demo

This library also has many string manipulation functions including wrap, split, join, strip, center, indent, dedent, and more. See their signatures in str.h.

Below is an example of ynot's Menu class, which makes it easy to create centered menus controlled with the arrow and enter keys.

ynot::Menu menu("sample menu", { "create", "list", "edit", "delete", "help", "settings", "exit" });
string choice = menu.run();
ynot::print("\nYou chose " + choice);

menu demo

Here's an example of getline_ac which gets a line of input while giving autocomplete suggestions (not autocorrect) and has optional built-in input validation:

ynot::print(" Enter a month: ");
string month = ynot::getline_ac({ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" });
ynot::print("\n You chose " + month);

autocomplete demo

Below is another example. With ynot's Paginator class, you can cleanly present long pieces of text in a terminal. The dedent function removes indentation from a multiline string.

string article_title = "3.6 Git Branching - Rebasing";
string article_body = ynot::dedent(R"(
    Article body here.
    Indent with tabs or spaces, not both.)");
string line_prefix = "\n    ";
ynot::Paginator paginator(article_title, article_body, line_prefix);
paginator.run();

paginator demo

The sample text is from git-scm.com.

multithreading with terminal.h

If your app uses multiple threads that call functions in terminal.h, you can prevent race conditions by combining strings before printing.

Race condition example:

string message;
int x, y, green;

...

ynot::set_cursor_coords(x, y);  // set_cursor_coords prints an ANSI code
ynot::print_rgb(0, green, 0, message);

race condition example

Each character is supposed to get steadily darker after it appears on screen, but sometimes the print_rgb function in one thread ends up being called between the set_cursor_coords and print_rgb calls in another thread.

Prevent this output scrambling by combining all strings into one before printing. The terminal.h functions that start with ret_ return strings instead of printing them so that you can wait to print until after combining strings.

string coord_str = ynot::ret_set_cursor_coords(x, y);
ynot::print_rgb(0, green, 0, coord_str + message);

matrix demo

You can see all of the code for what's shown in the gif here.