All Projects → KazDragon → terminalpp

KazDragon / terminalpp

Licence: MIT license
A C++ library for interacting with ANSI terminal windows.

Programming Languages

C++
36643 projects - #6 most used programming language
CMake
9771 projects

Projects that are alternatives of or similar to terminalpp

Chalk
🖍 Terminal string styling done right
Stars: ✭ 17,566 (+25732.35%)
Mutual labels:  terminal-emulators, ansi-escape-codes
Macterm
Terminal emulator for macOS with 24-bit color, bitmap and vector graphics.
Stars: ✭ 162 (+138.24%)
Mutual labels:  terminal-emulators
Alacritty
Alacritty is a modern terminal emulator that comes with sensible defaults, but allows for extensive configuration. By integrating with other applications, rather than reimplementing their functionality, it manages to provide a flexible set of features with high performance. The supported platforms currently consist of BSD, Linux, macOS and Windows.
Stars: ✭ 36,273 (+53242.65%)
Mutual labels:  terminal-emulators
Hyper
A terminal built on web technologies
Stars: ✭ 37,504 (+55052.94%)
Mutual labels:  terminal-emulators
Webterminal
ssh rdp vnc telnet sftp bastion/jump web putty xshell terminal jumpserver audit realtime monitor rz/sz 堡垒机 云桌面 linux devops sftp websocket file management rz/sz otp 自动化运维 审计 录像 文件管理 sftp上传 实时监控 录像回放 网页版rz/sz上传下载/动态口令 django
Stars: ✭ 1,124 (+1552.94%)
Mutual labels:  terminal-emulators
Pyxtermjs
A fully functional terminal in your browser.
Stars: ✭ 127 (+86.76%)
Mutual labels:  terminal-emulators
Jterminal
JTerminal is a (roughly) VT100-compatible terminal emulator for Swing-based Java applications.
Stars: ✭ 23 (-66.18%)
Mutual labels:  terminal-emulators
Aminal
🌘 Darktile is a GPU rendered terminal emulator designed for tiling window managers.
Stars: ✭ 2,663 (+3816.18%)
Mutual labels:  terminal-emulators
Extraterm
The swiss army chainsaw of terminal emulators
Stars: ✭ 1,922 (+2726.47%)
Mutual labels:  terminal-emulators
Snowflake
Graphical SFTP client and terminal emulator with helpful utilities
Stars: ✭ 1,676 (+2364.71%)
Mutual labels:  terminal-emulators
Cancer
It's terminal.
Stars: ✭ 98 (+44.12%)
Mutual labels:  terminal-emulators
React Console
Simple react console emulator
Stars: ✭ 64 (-5.88%)
Mutual labels:  terminal-emulators
Kitty
Cross-platform, fast, feature-rich, GPU based terminal
Stars: ✭ 13,011 (+19033.82%)
Mutual labels:  terminal-emulators
Alacritty Debian
Debian packages for alacritty.
Stars: ✭ 34 (-50%)
Mutual labels:  terminal-emulators
Iterm2 Borderless
Borderless iTerm2 patch with a few extra features
Stars: ✭ 165 (+142.65%)
Mutual labels:  terminal-emulators
Teds Terminal
A modern terminal emulator with high DPI support, mouse wheel scaling, 32-bit colour and tty compatible.
Stars: ✭ 20 (-70.59%)
Mutual labels:  terminal-emulators
Awesome Terminals
Terminal Emulators
Stars: ✭ 80 (+17.65%)
Mutual labels:  terminal-emulators
Wayst
A simple terminal emulator
Stars: ✭ 117 (+72.06%)
Mutual labels:  terminal-emulators
Contour
Modern C++ Terminal Emulator
Stars: ✭ 191 (+180.88%)
Mutual labels:  terminal-emulators
Terminalfx
Java FX Terminal Emulator
Stars: ✭ 187 (+175%)
Mutual labels:  terminal-emulators

Terminal++

Documentation License MSVC Build status Linux Build status Coverage Status Codacy Badge

Terminal++

A C++ library for interacting with ANSI/VT100 terminal or terminal emulator displays.

Requirements

Terminal++ requires a C++17 compiler and the following libraries:

  • Boost (At least version 1.69.0)
  • libfmt (At least version 5.3)
  • (For testing only) Google Test

Installation - CMake

Terminal++ can be installed from source using CMake. This requires Boost, libfmt and any other dependencies to have been installed beforehand, using their own instructions, or for the call to cmake --configure to be adjusted appropriately (e.g. -DBOOST_ROOT=... or -Dfmt_DIR=...). If you do not wish to install into a system directory, and thus avoid the use of sudo, you can also pass -DCMAKE_INSTALL_PREFIX=... into the cmake --configure call.

git clone https://github.com/KazDragon/terminalpp.git && cd terminalpp
mkdir build && cd build
cmake --configure -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
sudo cmake --install .

Installation - Conan

You can also use the Conan Package Manager to install Terminal++ and its dependencies.

See the tprint example for a minimalistic project that describes this setup.

Features / Roadmap

  1. A utility for creating strings with embedded ANSI attributes
  • terminalpp::string
  • This will be immediately useful in line-oriented programs to construct and output streams of attributed (coloured, emboldened, underlined, etc.) text.
  1. A utility for managing ANSI escape codes that are not bound to specific characters. For example, commands for moving the cursor, changing the screen's title, clearing the screen, etc.
  • terminalpp::terminal
  1. Utilities for managing screens of attributed characters
  • terminalpp::canvas
  • terminalpp::screen
  • This will be useful for those who wish to develop a more graphical or "curses-style" user interface.
  1. A database of terminal types and their associated behaviours
  • With some kind of application-specific terminal type detection, this would make it possible to write apps that automatically adjust to the most appropriate protocols supported by the client.

A set of classes that implement a windowing user interface are currently being implemented in the Munin project.

Status

Terminal++ is currently automatically tested using MSVC 2019 and GCC 9.4. For further information about the working status of the library, to report any bugs, or to make any feature requests, visit the Issues page. Feel free to discuss using Github Discussions!

The Basics

The purpose of the library is to be able to allow the usage of ANSI escape codes to their fullest potential in order to create fully-featured text-based applications. The use cases for such software range from interactive forms of command-line software up to GUI-style applications over the internet using terminal emulators such as Xterm, PuTTY, or even some MUD clients (e.g Tintin++).

At its most fundamental level, Terminal++ is in the business of manipulating character elements on the screen, where each element is encoded as a glyph, which describes the character that is presented to the user, and a series of non-character graphical attributes. These are encapsulated in the following classes:

  • terminalpp::glyph - represents a character (which may be ASCII or any UTF-8 value up to U+FFFF) and its character set (by default, this is the US_ASCII character set).
  • terminalpp::attribute - a collection of variables that describe the non-character graphical part of the output, such as the foreground and background colours, whether it is bold, underlined, and so on.

These are combined into Terminal++'s fundamental type, terminalpp::element.

The library's primary abstraction is the terminal class, which is a container for all the operations one might want to do on it. Because the terminal does not know whether you are sending data to the console, over a network connection or into a file, it uses a type-erased "channel" concept onto which these operations are mapped. This concept aligns closely with telnetpp::session, serverpp::tcp_socket and consolepp::console in the Telnet++, Server++ and Console++ libraries, respectively, for easier integration. Terminal++ also provides stdout_channel, which can serve for programs who do not require asynchronous input. This use of this is demonstrated in the examples below.

Strings

terminalpp::elements can be collected together using the terminalpp::string class. It has several constructors for different uses. For example, one of the constructors takes a std::string and an attribute to apply to all those characters for when you want something like print out a single red error message. In addition, there are the user-defined literal suffixes _ts (terminal string) and _ets (encoded terminal string) to help construct more complex strings.

Hello, World! project

#include <terminalpp/terminal.hpp>
#include <terminalpp/stdout_channel.hpp>

int main()
{
    using namespace terminalpp::literals;
    terminalpp::string text = "Hello, world!\n"_ts;

    terminalpp::stdout_channel channel;
    terminalpp::terminal terminal{channel};
    terminal << text;
}

// Constructs a terminalpp::string, and then prints it to the terminal as, "Hello, world!"

By using _ets, you can also encode attributes within the text. For example:

Encoded Hello, World! project

#include <terminalpp/terminal.hpp>
#include <terminalpp/stdout_channel.hpp>

int main()
{
    using namespace terminalpp::literals;
    terminalpp::string text = "\\[1Hello, \\[2World! \\x\\U263A\n"_ets;

    terminalpp::stdout_channel channel;
    terminalpp::terminal terminal{channel};
    terminal << text;
}

This prints out "Hello, " in red text, then "World!" in green text, and then a smiley face in the default colour. See the Wiki for more information about the attribute encoding used and its possibilities. It is also possible to change the attributes for each element programatically.

terminalpp::string text = ...;
text[0].attribute_.intensity_ = terminalpp::graphics::intensity::bold;

Terminals

At this point, you have everything you need for a standard command-line application that uses colour or other properties, such as you might see in the output of a CMake script or Google Test results, or even standard unix functions such as ls. But the terminal class allows for complete control over the terminal's appearance.

Positioned smiley project

#include <terminalpp/terminal.hpp>
#include <terminalpp/stdout_channel.hpp>

int main()
{
    using namespace terminalpp::literals;
    terminalpp::stdout_channel channel;
    terminalpp::terminal terminal{channel};

    terminal
        << terminalpp::save_cursor_position()
        << terminalpp::move_cursor({0, 0})
        << "\\U263A"_ets
        << terminalpp::restore_cursor_position();
}

This writes a smiley face in the (0, 0) position on the terminal -- the top-left corner. The cursor position is unchanged. The terminal uses a 0-based co-ordinate system where point (0, 0) is the top-left corner, and the co-ordinates are in (x, y) order.

Canvas and Screen

For even finer control of the terminal, the terminalpp::canvas class presents a grid of elements upon which you can "paint" the desired appearance of the terminal on a frame-by-frame by simply assigning to the appropriate co-ordinates:

int main()
{
    terminalpp::canvas canvas({80, 24});

    // Set the entire canvas to be the letter 'x' on a shocking pink
    // background.  Because, why not?
    terminalpp::element element('x');
    element.attribute_.background_colour_ = terminalpp::high_colour(5, 1, 2);

    for (terminalpp::coordinate_type y = 0; y < canvas.size().height; ++y)
    {
        for (terminalpp::coordinate_type x = 0; x < canvas.size().width; ++x)
        {
            canvas[x][y] = element;
        }
    }
}

Now, assigning elements to the canvas wont actually cause any immediate effect. For that, you would need to index over the entire canvas and output it, element-by-element, to a terminal. But it's very wasteful to output the entire screen each time that a small part of it changes.

To control this, we present the terminalpp::screen class, which represents a double-buffered approach to drawing the contents of a canvas. Its draw() member function will cause only the differences between the previously drawn canvas and the current canvas to be output, with efforts made to keep the output as small as possible. Note: it is assumed for the first canvas drawn, and for any canvas drawn after a change in output size, that everything has changed.

Shocking pink project

#include <terminalpp/terminal.hpp>
#include <terminalpp/canvas.hpp>
#include <terminalpp/screen.hpp>
#include <terminalpp/stdout_channel.hpp>

int main()
{
    terminalpp::stdout_channel channel;
    terminalpp::terminal terminal{channel};
    terminalpp::screen screen{terminal};
    terminalpp::canvas canvas({80, 24});

    // Set the entire canvas to be the letter 'x' on a shocking pink
    // background.  Because, why not?
    terminalpp::element element('x');
    element.attribute_.background_colour_ = terminalpp::high_colour(5, 1, 2);

    for (terminalpp::coordinate_type y = 0; y < canvas.size().height_; ++y)
    {
        for (terminalpp::coordinate_type x = 0; x < canvas.size().width_; ++x)
        {
            canvas[x][y] = element;
        }
    }

    screen.draw(canvas);
    // screen is now actually shocking pink.

    canvas[10][15].glyph_ = 'y';
    canvas[10][15].attribute_.background_colour_ = terminalpp::graphics::colour::blue;

    screen.draw(canvas);
    // screen is still shocking pink, but there is now a letter 'y' with a
    // blue background at position (10, 15).
}

It is also possible to read from a terminal. Standard C++ does not provide a way of reading from standard input asynchronously, so this requires operating system support. The Console++ library library implements this for certain platforms. Its consolepp::console class models the channel concept, so it fits right into a terminal. Using the terminal to read bytes from the console will convert the input into a sequence of ANSI protocol bytes into a series of tokens that can be inspected for regular text, control sequences (including function keys, arrow keys, etc.) and even mouse operations if that is set in the terminal's behaviour.

wait_for_mouse_click project

// ...

static boost::asio::io_context io_context;
static consolepp::console console{io_context};
static terminalpp::terminal terminal{
    console,
    [] {
        terminalpp::behaviour behaviour;
        behaviour.supports_basic_mouse_tracking = true;
        return behaviour;
    }()
};

// ...

int main()
{
    terminal << terminalpp::save_cursor_position()
             << terminalpp::use_alternate_screen_buffer()
             << terminalpp::enable_mouse()
             << terminalpp::erase_display()
             << terminalpp::move_cursor({0, 0})
             << "Click with a mouse button to exit!\n";
        
    schedule_async_read();
    io_context.run();

    terminal << terminalpp::disable_mouse()
             << terminalpp::use_normal_screen_buffer()
             << terminalpp::restore_cursor_position()
             << fmt::format("mouse clicked at ({},{})\n", mouse_position.x_, mouse_position.y_);
}

static void handle_token(terminalpp::token const &token);
static void schedule_async_read()
{
    terminal.async_read(
        [](terminalpp::tokens tokens) {
            for (auto const &token : tokens) {
                handle_token(token);
            }

            schedule_async_read();
        });
}

// ...
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].