Skip to content

michaeljclark/cutty

Repository files navigation

cutty

cutty is an OpenGL terminal emulator using FreeType and HarfBuzz.

cutty

Introduction

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 .

Building

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

Internals

This section describes the internal representation of the virtual line buffer used to store the terminal history.

Source organisation

The terminal source code is organized as follows:

  • app - window creation and event handling
  • capture - capture harness for running offscreen tests
  • cellgrid - layout of the virtual buffer to a physical buffer
  • process - creation of shell process attached to pseudo typewritter
  • render - generating batches and issues rendering commands
  • teletype - implementation of terminal protocol on a virtual buffer
  • translate - translating keyboard mappings to terminal protocol
  • typeface - font loading, measurement and metrics

Buffer coordinates

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.

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.

list of internal functions returning buffer coordinates

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