Code Monkey home page Code Monkey logo

osmanip's Introduction

A library used to manipulate the output stream of a program using ANSI escape sequences.

v4.5 license C++17
code size repo size total lines
codeq doc


Table of contents

Introduction

osmanip is a C++ library containing useful tools to manipulate ANSI escape sequences and customize the output stream of your programs. Within this tools you can add colors and styles to the printed strings, change cursor location on the terminal and manage other tools like progress bars and terminal graphics. Using this features may be very useful to adorn your general output stream log or to perform cursor operations.

This is a fully type- and thread-safe library with automatic memory management, with only indispensable dependencies.

It can be installed from source or via vcpkg. See this section for further details.

If you want to mention this software in one of your project / articles, please cite it.

If you use this library please tell me so I can add you to the list of know projects which use this library.

If you want to contribute to the repository, please read this file before. If you have ideas to propose write a post into the discussion section.

Code documentation is generated using Doxygen and can be accessed here. An extra wiki is also provided and contains how-to guides and many examples.

Colors and styles manipulators examples:

Progress bars examples:

2D terminal-graphics examples:

The software is and will stay free, but if you want to support me with a donation it would be really appreciated!

Buy Me A Coffee

Architectures support

Operating systems

  • Linux
    • Ubuntu (tested)
  • Windows (release 10 or higher)
    • Cygwin64 (tested)
    • MSYS2 (tested)
    • MinGW (tested)
    • WSL (tested)
    • Powershell (tested)
  • MacOS

Compilers

  • gcc:
    • C++17: 9/10/11/12
    • C++20: 10/11/12
  • clang:
    • C++17: 6/7/8/9/10/11/12/13/14/15
    • C++20: 9/10/11/12/13/14/15
  • MSVC:
    • C++17: 19 (only this one tested)
    • C++20: // (not tested yet)

List of features

ANSI escape sequences manipulators

#include <iostream>
#include <osmanip/manipulators/colsty.hpp>

// Print a red string
std::cout << osm::feat( osm::col, "red" ) << "This string is red!" << osm::feat( osm::rst, "color" );

// Print a bold string
std::cout << osm::feat( osm::sty, "red" ) << "This string is bold!" << osm::feat( osm::rst, "bd/ft" );
#include <iostream>
#include <osmanip/manipulators/cursor.hpp>

// Move the cursor right by 2 spaces
std::cout << osm::feat( osm::crs, "right", 2 ) << "Cursor moved!";
#include <iostream>
#include <osmanip/manipulators/cursor.hpp>

// Output a bell sound
std::cout << osm::feat( osm::tcs, "bell" );
#include <iostream>
#include <osmanip/manipulators/printer.hpp>

osm::Decorator my_shell;

// Change std::cout predefined style and color
my_shell.setColor( "green", std::cout );
my_shell.setStyle( "underlined", std::cout );

my_shell( std::cout ) << "The stdout stream has been changed using the Decorator class!" << "\n";

// Change std::cerr predefined style and color
my_shell.setColor( "red", std::cerr );
my_shell.setStyle( "bold italics", std::cerr ); // NOTE: added 2 styles

my_shell( std::cerr ) << "The stderr stream has been changed using the Decorator class!" << "\n";

More examples and how-to guides can be found here.

Why choosing this library for ANSI escape sequences manipulation:

  • All the functions used to manipulate these sequences are very easy to use and don't require complex code signatures.
  • All the most common ANSI sequences can be manipulated.
  • Using the Decorator class you can set the style of an output stream at the beginning of your program and keep it unchanged until the end.

Progress bars

#include <iostream>
#include <osmanip/progressbar/progressbar.hpp>
#include <osmanip/utility/options.hpp>

osm::ProgressBar<int> percentage_bar;

percentage_bar.setMin( 5 );
percentage_bar.setMax ( 46 );
percentage_bar.setStyle( "indicator", "%" );

std::cout << "This is a normal percentage bar: " << "\n";
osm::OPTION( osm::CURSOR::OFF ); // Hide cursor for better output rendering
 for ( int i = percentage_bar.getMin(); i < percentage_bar.getMax(); i++ )
  {
   percentage_bar.update( i );
   //Do some operations...
  }
osm::OPTION( osm::CURSOR::ON );

#include <iostream>
#include <osmanip/progressbar/progressbar.hpp>
#include <osmanip/utility/options.hpp>

osm::ProgressBar<int> loading_bar( 3, 25 );

loading_bar.setStyle( "loader", "#" );
loading_bar.setBrackets( "{", "}" );
loading_bar.setMessage( "processing..." );

std::cout << "This is a loading bar: with message: " << "\n";
osm::OPTION( osm::CURSOR::OFF ); // Hide cursor for better output rendering
for ( int i = loading_bar.getMin(); i < loading_bar.getMax(); i++ )
 {
  loading_bar.update( i );
  //Do some operations...
 }
osm::OPTION( osm::CURSOR::ON );

#include <iostream>
#include <osmanip/progressbar/progressbar.hpp>
#include <osmanip/utility/options.hpp>

osm::ProgressBar<int> progress_bar( 3, 25 );

progress_bar.setStyle( "complete", "%", "" );
progress_bar.setBrackets( "[", "]" );
progress_bar.setMessage( "elaborating..." );
progress_bar.setRemainingTimeFlag( "on" );
progress_bar.setColor( "red" );

std::cout << "This is a mixed progress bar with color and time remaining info: " << "\n";
osm::OPTION( osm::CURSOR::OFF ); // Hide cursor for better output rendering
for ( int i = progress_bar.getMin(); i < progress_bar.getMax(); i++ )
 {
  progress_bar.update( i );
  //Do some operations...
 }
osm::OPTION( osm::CURSOR::ON );

#include <iostream>
#include <osmanip/progressbar/progressbar.hpp>
#include <osmanip/utility/options.hpp>

osm::ProgressBar<int> spinner;

spinner.setMin( 2 );
spinner.setMax ( 33 );
spinner.setStyle( "spinner", "/-\\|" );

std::cout << "This is a progress spinner: " << "\n";
osm::OPTION( osm::CURSOR::OFF ); // Hide cursor for better output rendering
for ( int i = spinner.getMin(); i < spinner.getMax(); i++ )
 {
  spinner.update( i );
  //Do some operations...
 }
osm::OPTION( osm::CURSOR::ON );

  • Output redirection on file when using progress bars
#include <iostream>
#include <osmanip/progressbar/progress_bar.hpp>
#include <osmanip/redirection/output_redirector.hpp>
  
osm::OutputRedirector redirector( "output.txt" );

std::cout << "I am printing to the console!\n";

// Redirect output to the file
redirector.begin();

std::cout << "Now I am printing to a file!\n";

osm::ProgressBar<int> my_bar;
// ...

for( int i = my_bar.getMin(); i < my_bar.getMax(); i++ )
{
  // Flush the buffer at the start of each loop
  redirector.flush();

  my_bar.update( i );
}

// Return output to the console
redirector.end();

More examples and how-to guides can be found here.

Why choosing this library for progress bars? Some properties:

  • Extremely easy to use.
  • Compatible with positive or negative variable of any standard type (integer, float, double and others).
  • Maximum and minimum values can be set with any value you prefer and the progress bars will be self-built with respect to them.
  • Each progress bar feature can be fully customized (messages, style, color, brackets type, time remaining info etc...) regarding to your requirements. You can also choose to use only a progress indicator or a loading bar instead of a complete progress bar.
  • It is thread-safe, hence you can use also multiple progress bars simultaneously.

Terminal graphics

#include <osmanip/manipulators/colsty.hpp>
#include <osmanip/graphics/canvas.hpp>

osm::Canvas canvas(10,10);

canvas.setBackground( '.', osm::feat( osm::col, "bg white" ) + osm::feat( osm::col, "black" ) );
std::cout << "Display an animation in a canvas\n";

for( uint i = 0; i < 10; i++ )
 {
  canvas.clear();
  canvas.put( 0, 2, 'x' );
  canvas.put( i, 3, 'A', osm::feat( osm::col, "red" ) );
  canvas.put( 5, 0, 'B', osm::feat( osm::col, "blue" ) );
  canvas.put( 7, 8, 'Z', osm::feat( osm::col, "bg cyan" ) + osm::feat( osm::col, "black" ) + osm::feat( osm::sty, "bold" ) );
  canvas.refresh();
 }

#include <functional>
#include <osmanip/manipulators/colsty.hpp>
#include <osmanip/graphics/canvas.hpp>

osm::Plot2DCanvas plot_2d_canvas( 50, 20 );

std::cout << "\n" << "Plot2DCanvas with sin and cos" << "\n";
plot_2d_canvas.setBackground( ' ', osm::feat( osm::col, "bg white" ) );
plot_2d_canvas.enableFrame( true );
plot_2d_canvas.setFrame( osm::FrameStyle::BOX, osm::feat( osm::col, "bg white" ) + osm::feat( osm::col, "black" ) );
plot_2d_canvas.enableFrame( true );
plot_2d_canvas.setFrame( osm::FrameStyle::BOX, osm::feat( osm::col, "bg white" ) + osm::feat( osm::col, "black" ) );
plot_2d_canvas.setScale( 1/3.14, 0.2) ;

for( float i = 0; i < 40; i++ )
 {
  plot_2d_canvas.setOffset( i/3.14, -2 );
  plot_2d_canvas.clear();
  plot_2d_canvas.draw( std::function <float( float )>( []( float x ) -> 
                       float{ return std::cos( x ); } ), 'X', osm::feat( osm::col, "bg white" ) + osm::feat( osm::col, "bd red" ) );
  plot_2d_canvas.draw( std::function <float( float )>( []( float x ) -> 
                       float{ return std::sin( x ); } ), 'X', osm::feat( osm::col, "bg white" ) + osm::feat( osm::col, "bd blue" ) );
  plot_2d_canvas.refresh();
  sleep_for( milliseconds( 100 ) );
 }

More examples and how-to guides can be found here.

Why choosing this library for terminal graphics:

  • There are very few C++ libraries doing this job, and this is one of them.
  • High level of customizability.
  • A faster and most comfortable alternative to plot simple functions without the needing of GUI.

Extra support for UNICODE and ANSI on Windows

// Enable ANSI escape sequences
osm::OPTION( osm::ANSI::ON );
// doing some stuff...
osm::OPTION( osm::ANSI::OFF );
// Enable unicode characters
osm::OPTION( osm::UNICODECH::ON );
// doing some stuff...
osm::OPTION( osm::UNICODECH::OFF );

More examples and how-to guides can be found here.

Install and use

Install

Steps to be reproduced:

1) Download one of the releases of the repository

2) Unzip and enter the downloaded repository directory

3) Install and compile the library and its dependencies:

cmake -B build

Install:

sudo cmake --build build --target install

⚠️ sudo is not required on Windows.

Mandatory prerequisites (automatically installed with the script):

  • C++17 standard.
  • g++ compiler.
  • CMake (at least version 3.15).

Package managers

This is the list of available package managers for osmanip:

Use in your device

Tu use on or more headers of the library:

#include <osmanip/module_folder/module_name.hpp>

If you are using the library in a program, add the -losmanip flag to link source code.

⚠️: remember also to add -pthread flag if you want to use some thread-dependent libraries like ** progressbar/multi_progress_bar.hpp** .

Use with CMake

To get an installed version of the library:

find_package( osmanip )

then, to link it to a target:

target_link_libraries( ${TARGET} osmanip::osmanip )

Compile examples

Examples are compiled during the installation procedure.

To run all the examples:

./build/examples/osmanip_manipulators
./build/examples/osmanip_progressbar
./build/examples/osmanip_graphics
./build/examples/osmanip_redirection

⚠️ executables end with .exe if you are on Windows of course.

Developer debug mode and tests

To compile tests you must build the app in debug mode:

cmake -B build -DCMAKE_BUILD_TYPE=Debug
sudo cmake --build build --target install

⚠️ remember to install the library before launching include tests, or an error will appear. ⚠️ if you want to build the library in debug mode, but without compiling tests use also the option -DOSMANIP_TESTS=OFF.

Tests are produced using -Wall -Wextra -pedantic flags. To check them you need some prerequisites:

The doctest package is automatically installed with the installation step. Also the clang-format package is required. The format procedure is performed automatically when compiling.

To launch all tests simultaneously:

./test/all_tests.sh

EXTRA: to check that only the needed headers are include use this script:

./test/IWYU.sh

Todo

  • Separate progress bar class into multiple files.
  • Add an elapsedTime() method to the ProgressBar class, to show elapsed progress bar time and substitute it to the already existing getTime() method.
  • Benchmarking and other studies with respect to similar libraries (already in progress here).
  • Add a wiki section for output_redirector.

List of know projects which use this library

Credits

Project leaders


Gianluca Bianco

Other contributors


MiguelMJ

Ted Lyngmo

myermo

nick-botticelli

Joel Thomas

oz_10

Kai Pastor

Stargazers over time

Stargazers over time

osmanip's People

Contributors

allcontributors[bot] avatar dg0yt avatar joeletho avatar justwhit3 avatar miguelmj avatar nick-botticelli 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

osmanip's Issues

Unable to compile examples and tests on MSVC (error got from CodeQL analysis workflow)

Hi @joeletho ,

I set up the CMake building process, but an error occurs when trying to compile with MSVC and it seems it is related to output_redirector.cpp. As you can see from running the CodeQL workflow for Windows, this error occurs:

D:\a\osmanip\osmanip\src\utility\output_redirector.cpp(76,4): error C2512: 'std::basic_ostream<char,std::char_traits<char>>': no appropriate default constructor available [D:\a\osmanip\osmanip\build\osmanip.vcxproj]

and subsequently:

D:\a\osmanip\osmanip\src\utility\output_redirector.cpp(73,13): error C2665: 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string': no overloaded function could convert all the argument types [D:\a\osmanip\osmanip\build\osmanip.vcxproj]

Do you have any idea of what's happening? Could you please investigate this issue and try to fix it? Thanks.

Install script raising an error.

Executing ./scripts/install.sh raises the following error:

Doctest is not installed, cannot compile the test codes!

./scripts/install.sh: line 22: eco: order not found.
make: *** No rule to make target `bin/main'. Stop.
Compilation failed!

I'm opening the issue because in the documentation it is stated that Doctest is optional.

Improve the progress bar code structure

The progress bar header has been written some time ago and the code structure can be improved. For example, it can be separated in different classes, regarding the type of the progress bar (indicator, spinner, etc..) and a base mother class can be created, which other classes inherit basic features.

Manipulators wrapping

On Reddit, a user asked for a better way to use manipulators and suggested wrapping them in order to use them in a more compact way:

std::cout << osm::col("red");

I personally disagree in this choice, but if a good proposal works good I will probably integrate it in the library without hesitation.

Make failing because of doctest::detail::MessageBuilder

When building with

make

The following error occurs:

In file included from test/tests_helper_tools.cpp:3:
test/tests_helper_tools.cpp: In lambda function:
test/tests_helper_tools.cpp:15:32: error: no match for ‘operator+’ (operand types are ‘doctest::detail::MessageBuilder’ and ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’})
   15 | #define test_string_hp "first" +                            \
      |                                ^
   16 |                        static_cast <std::string>(" \"") +   \
      |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                        |
      |                        std::string {aka std::__cxx11::basic_string<char>}
test/tests_helper_tools.cpp:65:80: note: in expansion of macro ‘test_string_hp’
   65 |   CHECK_THROWS_MESSAGE( throw( runtime_error_func( "first", var, "second" ) ), test_string_hp );
      |                                                                                ^~~~~~~~~~~~~~

As I'm not familiar with doctest, I would just suggest to separate the tests into their own build, with something like make tests.
Cheers!

Use of `NULL` and `nullptr` as numeric value

NULL is implementation defined. This means every compiler is free to choose how the macro expands. IMHO, you should try to avoid implementation defined behavior as they don't have the best portability, and may change between compilers or even different versions of the same compiler.

Most compilers since C++11 expand NULL to nullptr which is a nullptr_t type and cannot be assigned to non-pointer types; i.e., use of int max = NULL; is an error.

error: cannot initialize a variable of type 'int' with an rvalue of type 'nullptr_t'
    int max = NULL;
        ^     ~~~~

Check out cppreference article on NULL for information about the changes to NULL.

That said, it looks like you should be using 0 in most of this code b/c you're assigning NULL to integer/floating point types, which is an compile-time error on compilers expanding NULL to nullptr.

Describe the bug
Assigning NULL to non-pointer types.
Assigning nullptr to non-pointer types.

Fix
Without refactoring the code, worked around the problem by changing uses of NULL to 0 and nullptr to 0.

Environment

  • OS: OpenBSD
  • Version: 7.1
  • Clang: OpenBSD clang version 13.0.0

I opened the same issue on arsenalgear-cpp.

Progressbar doc test failing due to static member varible

Hi @JustWhit3,
I'm implementing OutputRedirector tests and they've caused ProgressBar tests to throw an exception when it attempts to set an already existing style:

[doctest] run with "--help" for options
===============================================================================
test/unit_tests/progressbar/tests_progress_bar.cpp:39:
TEST CASE:  Testing the ProgressBar class methods.<float>
  Testing addStyle method.

test/unit_tests/progressbar/tests_progress_bar.cpp:39: ERROR: test case THREW exception: exception thrown in subcase - will translate later when the whole test case has been exited (cannot translate while there is an active exception)

===============================================================================
test/unit_tests/progressbar/tests_progress_bar.cpp:39:
TEST CASE:  Testing the ProgressBar class methods.<float>

test/unit_tests/progressbar/tests_progress_bar.cpp:39: ERROR: test case THREW exception: Inserted ProgressBar style "|100" is already available!

===============================================================================
[doctest] test cases:     15 |     13 passed |      2 failed |      0 skipped
[doctest] assertions:   1130 |   1129 passed |      1 failed |
[doctest] Status: FAILURE!

I'm guessing that since the ProgressBar uses a static style map, OutputRedirector it adds the style to the before the ProgressBar performs its own test.

Is there a way to the style map before/after use?

Add other cursor methods

Add other cursor methods to the proper header. Example:

printf("\x1b%d", 7);    // Save cursor
printf("\x1b%d", 8);    // Restore saved cursor
printf("\x1b[6n");    // Print current cursor position

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.