cutty is an OpenGL terminal emulator using FreeType and HarfBuzz.
The cutty terminal emulator is a simple, maintainable, cross-platform and standards compliant terminal emulator written in portable C++17. The cutty terminal emulator is a work in progress and is not feature complete nevertheless it provides a fast and competent basis to explore evolution of the DEC/VT/ANSI/xterm protocols.
The cutty terminal emulator currently supports the following features:
- Anti-aliased truetype rendering for UTF-8 text with emoji.
- Xterm 16, 256, and 16M colors, bold and underlined styled text.
- Compressed history with scrollbars and wheel mouse support.
- Flexible input translation layer for adding key bindings.
- Additional columns for line numbers and time stamps.
The terminal emulator supports standalone builds on macOS and Linux. All dependencies required to build cutty besides OpenGL are included. Included dependencies are statically linked and the GLAD OpenGL and GLFW window system loaders are used to minimize runtime dependencies.
The cutty terminal includes these submodules: FreeType †, HarfBuzz †, msdfgen †, zlib †, brotli †, bzip2 †, libpng †.
The cutty terminal emulator uses cmake to build. All runtime dependencies besides OpenGL are included as submodules. tesseract OCR and osmesa are required to run the tests. It is recommended to build cutty using Ninja:
cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build -- --verbose
This section describes the internal representation of the virtual line buffer used to store the terminal history.
The terminal source code is organized as follows:
app
- window creation and event handlingcapture
- capture harness for running offscreen testscellgrid
- layout of the virtual buffer to a physical bufferprocess
- creation of shell process attached to pseudo typewritterrender
- generating batches and issues rendering commandsteletype
- implementation of terminal protocol on a virtual buffertranslate
- translating keyboard mappings to terminal protocoltypeface
- font loading, measurement and metrics
The terminal internally uses three different types of coordinates:
- logical {line,offset}-addressing
- (0,0) is the first character in the logical history
- physical {row,column}-addressing
- (0,0) is the first character in the physical layout
- protocol {row,column}-addressing
- (1,1) is the top left cell of the visble portion
The following diagram shows the relationship between logical, physical, and protocol coordinates.
The virtual line buffer uses logical {line,offset}-addressing internally to record text selection ranges and to store the position of the cursor. Logical addresses are translated to physical {row,column}-addressing to map the buffer to line wrapped physical coordinates to support precise scrolling of the buffer. Protocol addresses are the screen coordinates used in escape codes to address the visible portion of the terminal viewport.
Forward and reverse indexes are maintained that map from logical buffer addresses to physical buffer addresses. Index are incrementally recomputed when the viewport size changes. If the buffer is edited, care must be taken to recompute the cursor position based on the current window dimensions and the location of line feeds.
function | basis | description |
---|---|---|
cursor_line() |
logical | line the cursor is at currently |
cursor_offset() |
logical | offset the cursor is at currently |
total_rows() |
physical | total number of rows after wrap |
total_cols() |
physical | total number of columns after wrap |
top_row() |
physical | row number of the topmost line |
cursor_row() |
physical | row number of the cursor line |
visible_rows() |
protocol | window size in rows (ws_rows ) |
visible_cols() |
protocol | window size in cols (ws_cols ) |
scroll_top() |
protocol | scroll region top row |
scroll_bottom() |
protocol | scroll region bottom row |