Библиотека вывода с использованием escape-последовательностей

от автора


Osmanip – это библиотека C++, предоставляющая полезные механизмы для работы с управляющими последовательностями ANSI и настройки потока вывода программ. С помощью этих механизмов вы можете оформлять выводимые строки различными цветами и стилями, изменять расположение курсора в терминале и регулировать прочие компоненты вроде индикаторов выполнения и графики. Весь этот функционал будет очень полезен для придания желаемого вида общему потоку вывода программы или для выполнения операций с курсором.

Если вы захотите использовать это ПО в своём проекте или упомянуть в статье, будьте добры, указывайте на его ссылку.

Если у вас возникнет желание внести свой вклад в репозиторий, сначала прочтите этот файл.

Документация кода сгенерирована при помощи Doxygen и доступна здесь. Помимо этого, есть ещё справочная страница GitHub, которая содержит дополнительные практические инструкции и множество примеров.

Вот некоторые из них:


Цвета и стили


Индикаторы выполнения


Двухмерная графика в терминале

Поддерживаемые ОС:

  • Linux;
    • Ubuntu (протестировано);
  • Windows (версия 10 и выше);
    • Cygwin64 (протестировано);
    • MSYS2 (протестировано);
    • MinGW (протестировано);
    • WSL (протестировано);
  • MacOS.

▍ Новости последних релизов

  • добавлен класс OS_Decorator для удобства управления стилизацией потока вывода программы;
  • добавлена справочная страница библиотеки;
  • добавлена полная поддержка Windows и MacOS;

Список возможностей

▍ Механизмы работы с escape-последовательностями ANSI

Управление цветом и стилем:

#include <iostream> #include <osmanip/manipulators/colsty.hpp>  // Вывод красной строки std::cout << osm::feat( osm::col, "red" ) << "This string is red!" << osm::feat( osm::rst, "color" );  // Вывод жирной строки std::cout << osm::feat( osm::sty, "red" ) << "This string is bold!" << osm::feat( osm::rst, "bd/ft" );

Управление курсором:

#include <iostream> #include <osmanip/manipulators/cursor.hpp>  // Перемещение курсора вправо на два пробела std::cout << osm::feat( osm::crs, "right", 2 ) << "Cursor moved!";

Управляющие последовательности для терминала:

#include <iostream> #include <osmanip/manipulators/cursor.hpp>  // Вывод звука колокольчика std::cout << osm::feat( osm::tcs, "bell" );

Дополнительные функции:

#include <iostream> #include <osmanip/manipulators/printer.hpp>  // Аналог Python функции "print" osm::print( std::cout, "This is the ", "\"print\" ",             "function for the normal output stream! ", 100, "% working!" );

Класс для управления стилизацией вывода программы:

#include <iostream> #include <osmanip/manipulators/printer.hpp>  osm::OS_Decorator my_shell;  // Изменение предопределённого стиля и цвета std::cout my_shell.setColor( "green", std::cout ); my_shell.setStyle( "underlined", std::cout );  my_shell( std::cout ) << "The stdout stream has been changed                           using the OS_Decorator class!" << "\n";  // Изменение предопределённого стиля и цвета std::cerr my_shell.setColor( "red", std::cerr ); my_shell.setStyle( "bold italics", std::cerr ); // Примечание: добавлено 2 стиля  my_shell( std::cerr ) << "The stderr stream has been changed                           using the OS_Decorator class!" << "\n";

Дополнительные примеры и инструкции можно найти здесь.

Почему для работы с escape-последовательностями стоит выбрать именно эту библиотеку:

  • все функции использования этих последовательностей очень просты в использовании и не требуют сложных сигнатур кода.
  • можно работать со всеми самыми популярными последовательностями.
  • с помощью класса OS Decorator можно устанавливать стиль вывода в начале программы, сохраняя его неизменным до ее завершения.

▍ Индикаторы выполнения

Процентный индикатор:

#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 ); // Сокрытие курсора для лучшей отрисовки вывода  for ( int i = percentage_bar.getMin(); i < percentage_bar.getMax(); i++ )   {    percentage_bar.update( i );    //Выполнение операций...   } 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 normal loading bar: " << "\n"; osm::OPTION( osm::CURSOR::OFF ); // Сокрытие курсора для лучшей отрисовки вывода for ( int i = loading_bar.getMin(); i < loading_bar.getMax(); i++ )  {   loading_bar.update( i );   //Выполнение операций...  } 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 ); // Сокрытие курсора для лучшей отрисовки вывода for ( int i = progress_bar.getMin(); i < progress_bar.getMax(); i++ )  {   progress_bar.update( i );   //Выполнение операций...  } 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 ); // Сокрытие курсора для лучшей отрисовки вывода for ( int i = spinner.getMin(); i < spinner.getMax(); i++ )  {   spinner.update( i );   //Выполнение операций...  } osm::OPTION( osm::CURSOR::ON );

Дополнительные примеры и инструкции можно найти здесь.

Преимущества использования именно этой библиотеки для реализации индикаторов выполнения:

  • крайняя простота применения;
  • поддерживает положительные и отрицательные переменные любого стандартного типа (integer, float, double и прочих);
  • в качестве максимума и минимума можно установить любые нужные значения, и индикатор будет построен относительно них;
  • каждый элемент индикатора настраивается (сообщения, стиль, цвет, тип скобок, оставшееся время и т.д.). Также можно использовать вместо смешанного прогресс бара только индикацию выполнения или загрузки.
  • потокобезопасность, то есть можно одновременно использовать множество индикаторов выполнения.

▍ Графика в терминале

Создание анимаций:

#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();  }

Построение 2D-графиков:

#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 ) );  }

Дополнительные примеры и инструкции можно найти здесь.

Преимущества реализации графики в терминале с помощью этой библиотеки:

  • подобный функционал обеспечивается очень немногими библиотеками C++, и эта одна из них;
  • высокий уровень кастомизируемости;
  • более шустрая и удобная альтернатива отрисовке графиков простых функций без потребности в GUI.

▍ Дополнительная поддержка UNICODE и ANSI в Windows

// Активация escape-последовательностей ANSI osm::OPTION( osm::ANSI::ON ); // выполнение нужных действий... osm::OPTION( osm::ANSI::ON );   // Активация символов unicode osm::OPTION( osm::UNICODECH::ON ); // выполнение нужных действий... osm::OPTION( osm::UNICODECH::ON );

Дополнительные примеры и инструкции можно найти здесь.

Установка и использование

▍ Установка

1. Скачать один из релизов репозитория.

2. Распаковать архив и открыть каталог.

3. Установить и скомпилировать библиотеку с зависимостями при помощи установочного скрипта.

./script/install.sh

Этот скрипт поддерживает установку под Ubuntu, MacOS, Windows и прочими операционными системами.

Примечание: если вы работаете в Cygwin64, то можете получить ошибку, связанную с символом \r. Чтобы её избежать, предварительно выполните для скрипта команду dos2unix.

В результате в каталоге /usr/lib создаётся новая библиотека, а файлы заголовков устанавливаются по пути /usr/include.

Примечание: если вы работаете в MacOS или Windows, пути будут несколько отличаться (см. install.sh).

Обязательные программы (устанавливаются автоматически скриптом):

Необязательные программы, для разработчиков:

  • Valgrind для запуска скрипта debug.sh;
  • Cppcheck для запуска скрипта debug.sh;
  • Clang formatter для подготовки кода к пул-реквестам;
  • wget для скачивания дополнительных репозиториев зависимостей;
  • unzip для распаковки архивных каталогов во время скачивания и установки;
  • Doxygen для генерации документации при разработке;
  • doctest для тестирования;
  • hurry.filesize для скрипта size_of_dir.py;
  • termcolor для скрипта size_of_dir.py.

4. Дополнительно: для периодического обновления репозитория:

./scripts/update.sh ./scripts/install.sh

5. Дополнительно: для деинсталляции репозитория из системы:

./scripts/uninstall.sh

▍ Использование на вашем устройстве

Для использования одного или более заголовков библиотеки:

#include <osmanip/module_folder/module_name.hpp>

В случае использования библиотеки в программе добавьте флаг -losmanip для линковки исходного кода.

Примечание: не забудьте также добавить флаг -pthread, если хотите использовать потокозависимые библиотеки вроде progressbar/multi_progress_bar.hpp.

▍ Компиляция примеров и тестирование

Компиляция примеров:

make main

Запуск примеров:

./bin/manipulators ./bin/progressbar ./bin/graphics

Примечание: если вы работаете в Windows, исполняемые файлы оканчиваются на .exe.

Компиляция тестов:

make tests

Запуск тестов:

./bin/tests

Также есть вариант вернуться обратно в состояние до компиляции. Для этого просто выполните:

make clean

▍ Полезные скрипты

Я добавил кое-какие дополнительные полезные скрипты в каталог scripts. После компиляции исходного кода их можно будет запустить из домашнего каталога репозитория.

Скрипт debug.sh используется для запуска отладчиков Valgrind и Cppcheck для всего кода.

Valgrind можно запустить через отдельный исполняемый файл:

./scripts/debug_cpp.sh [valgrind-tool-name] [executable-name]

Структура репозитория

osmanip/ ├── .github/ │   ├── workflows/ │   │   ├── DocGenerator.yml │   │   ├── codeql-analysis.yml ├── img/ ├── include/ │   ├── graphics/ │   │   ├── canvas.hpp │   │   ├── plot_2D.hpp │   ├── manipulators/ │   │   ├── colsty.hpp │   │   ├── cursor.hpp │   │   ├── common.hpp │   │   ├── printer.hpp │   ├── progressbar/ │   │   ├── progress_bar.hpp │   │   ├── multi_progress_bar.hpp │   ├── utility/ │   │   ├── windows.hpp │   │   ├── options.hpp ├── src/ │   ├── graphics/ │   │   ├── canvas.cpp │   │   ├── plot_2D.cpp │   ├── manipulators/ │   │   ├── colsty.cpp │   │   ├── cursor.cpp │   │   ├── common.cpp │   │   ├── printer.hpp │   ├── progressbar/ │   │   ├── progress_bar.cpp │   │   ├── multi_progress_bar.cpp │   ├── utility/ │   │   ├── windows.cpp ├── examples/ │   ├── manipulators.cpp │   ├── progressbar.cpp │   ├── graphics.cpp ├── scripts/ │   ├── debug.sh │   ├── install.sh │   ├── uninstall.sh │   ├── update.sh │   ├── size_of_dir.py ├── test/ │   ├── graphics/ │   │   ├── tests_canvas.cpp │   │   ├── tests_plot_2D.cpp │   ├── manipulators/ │   │   ├── tests_common.cpp │   │   ├── tests_colsty.cpp │   │   ├── tests_cursor.cpp │   │   ├── tests_printer.cpp │   ├── progressbar/ │   │   ├── tests_progress_bar.cpp │   │   ├── tests_multi_progress_bar.cpp │── README.md │── CONTRIBUTING.md │── LICENSE │── CITATION.cff │── Makefile │── Doxyfile │── .gitignore │── .clang-format │── .valgrindrc │── .gitignore │── .all-contributorsrc

▍ Дальнейшие планы

  • Работа с escape-последовательностями ANSI:
    • добавить механизмы работы с символами UNICODE;
    • добавить в класс OS_decorator новые методы;
    • реализовать перенаправление файлов при работе с выводом.
  • Индикаторы выполнения:
    • добавить метод elapsedTime() для отображения пройденного времени выполнения, заменив им существующий метод getTime();
  • Графика для терминала:
    • добавить метод для сопровождения графиков легендой;
    • добавить автоматическое изменение размера графика;
    • добавить опцию отображения осей;
    • расширить 2D графику до 3D;
  • Системный функционал:
    • улучшить компиляцию с помощью CMake;
    • сравнить библиотеку с аналогами на основе бенчмарков и прочих исследований.


ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/679758/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *