[Перевод] Библиотека вывода с использованием escape-последовательностей
Osmanip — это библиотека C++, предоставляющая полезные механизмы для работы с управляющими последовательностями ANSI и настройки потока вывода программ. С помощью этих механизмов вы можете оформлять выводимые строки различными цветами и стилями, изменять расположение курсора в терминале и регулировать прочие компоненты вроде индикаторов выполнения и графики. Весь этот функционал будет очень полезен для придания желаемого вида общему потоку вывода программы или для выполнения операций с курсором.
Если вы захотите использовать это ПО в своём проекте или упомянуть в статье, будьте добры, указывайте на его ссылку.
Если у вас возникнет желание внести свой вклад в репозиторий, сначала прочтите этот файл.
Документация кода сгенерирована при помощи Doxygen и доступна здесь. Помимо этого, есть ещё справочная страница GitHub, которая содержит дополнительные практические инструкции и множество примеров.
Вот некоторые из них:
Цвета и стили
Индикаторы выполнения
Двухмерная графика в терминале
Поддерживаемые ОС:
- Linux;
- Ubuntu (протестировано);
- Windows (версия 10 и выше);
- Cygwin64 (протестировано);
- MSYS2 (протестировано);
- MinGW (протестировано);
- WSL (протестировано);
- MacOS.
▍ Новости последних релизов
- добавлен класс
OS_Decorator
для удобства управления стилизацией потока вывода программы; - добавлена справочная страница библиотеки;
- добавлена полная поддержка Windows и MacOS;
Список возможностей
▍ Механизмы работы с escape-последовательностями ANSI
Управление цветом и стилем:
#include
#include
// Вывод красной строки
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
#include
// Перемещение курсора вправо на два пробела
std::cout << osm::feat( osm::crs, "right", 2 ) << "Cursor moved!";
Управляющие последовательности для терминала:
#include
#include
// Вывод звука колокольчика
std::cout << osm::feat( osm::tcs, "bell" );
Дополнительные функции:
#include
#include
// Аналог Python функции "print"
osm::print( std::cout, "This is the ", "\"print\" ",
"function for the normal output stream! ", 100, "% working!" );
Класс для управления стилизацией вывода программы:
#include
#include
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
#include
#include
osm::ProgressBar 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
#include
#include
osm::ProgressBar 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
#include
#include
osm::ProgressBar 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
#include
#include
osm::ProgressBar 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
#include
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
#include
#include
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 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 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
В случае использования библиотеки в программе добавьте флаг -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;
- сравнить библиотеку с аналогами на основе бенчмарков и прочих исследований.