Skip to content

Anuta286/terminal-buffer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 

Repository files navigation

Terminal Buffer

A terminal text buffer — the core data structure that terminal emulators use to store and manipulate displayed text.

Solution

Structure

The implementation is split into five classes:

  • Color — a terminal color identified by a hex string. Provides 16 named ANSI constants and two defaults (foreground/background).
  • Style — an enum of visual flags: BOLD, ITALIC, UNDERLINE.
  • CellAttributes — an immutable value object grouping foreground color, background color, and a set of style flags. Acts as the "current pen" of the buffer.
  • Cell — an immutable value object representing one grid position: a character plus the attributes active when it was written.
  • Line — a mutable fixed-width array of cells representing one row in the grid.
  • TerminalBuffer — the main class. Owns a Line[] screen and a Deque<Line> scrollback, and exposes all editing and content access operations.

Key decisions

Cell and CellAttributes are immutable. Both are used as values, not entities. Making them immutable means they can be safely shared — Cell.EMPTY and CellAttributes.DEFAULT are singletons referenced by every blank cell in the grid without defensive copying. It also prevents a subtle bug where changing the current pen color would retroactively affect already-written cells if they held a mutable reference.

Line is mutable. Lines are modified in place on every keystroke. Creating a new Line object per character would generate significant garbage in a hot path. Mutability is safe here because the buffer fully controls line ownership — lines in scrollback are never modified after being pushed off the screen (a copy is made via the copy constructor before adding to scrollback).

scrollUp() is the single growth point for scrollback. All operations that cause lines to leave the screen — write() wrapping past the last row, insert() cascade overflow, and insertEmptyLine() — go through scrollUp(). This keeps the eviction and capacity logic in one place.

Logical row indexing across scrollback and screen. Content access methods use a single logical row index where 0 is the oldest scrollback line and scrollbackSize + N is screen row N. This gives callers a uniform way to address the entire buffer history without needing to know which region a row lives in.

advanceCursor() is extracted as a private method. Both write() and insert() share identical cursor advance logic. Extracting it removes the duplication and ensures both operations stay consistent if the wrapping behavior ever changes.

Trade-offs and known limitations

getLine() iterates the deque. ArrayDeque does not support O(1) index access. Every call to getChar(), getAttrsAt(), or getLineText() for a scrollback row iterates from the front of the deque. For a scrollback of thousands of lines this becomes O(n) per access. A better structure would be an ArrayList with a start-index pointer to simulate a circular buffer — O(1) random access with O(1) amortized eviction from the front.

Color is modeled as a hex string. The current Color class stores colors as RGB hex strings, which is intuitive but couples the model to a display format. A cleaner model would store the ANSI color index (0–15) as an integer and leave hex conversion to the rendering layer. This also makes equality checks slightly cheaper.

Possible improvements

  • Replace ArrayDeque<Line> with an ArrayList<Line> and a rolling start index for O(1) scrollback access.
  • Add wide character support with a cellWidth field on Cell and corresponding handling in Line.insertCellAt() and TerminalBuffer.advanceCursor().
  • Add resize(int newWidth, int newHeight) with a chosen re-flow strategy (e.g. rewrap content to the new width).
  • Move tests into separate packages (buffer for unit tests of Line, Cell etc. and buffer.integration for TerminalBuffer tests) to reflect the distinction between unit and integration-level tests.
  • Add 256-color and RGB color support by extending the Color model with additional subclasses alongside Standard.

About

Terminal text buffer implementation — a grid-based data structure for storing and manipulating terminal screen content, including scrollback history, cursor management, and cell-level attributes (colors, styles).

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages