
Ansiform is a small Haskell library for building visual command line interfaces. It provides a declarative format DSL for styled text, rules, aligned lines, lists, groups, tables, paragraphs and multi-section pages.
Builders are pure and produce immutable values. A thin drawing layer writes those values to the terminal and keeps track of how many lines were printed, so a page can be amended, replaced or redrawn in place.
Formerly known as Vis. Ansiform is a terminal formatting library, unrelated to the JavaScript vis-network graph visualization library or to the Hackage package Vis (3D graphics). See Naming.
Current version: 1.0.0.1.
Repository: https://github.com/Tralen/ansiform.
Stack
Haskell with Cabal. Stack is not used.
Versioning
PVP, single-sourced from the ansiform.cabal file.
- Patch: fixes and minor refinements.
- Minor: new user-facing features or screens.
- Major 2: data model breaking changes.
- Major 1: major release milestones.
Features
- ANSI colors, bold, italic and underline, with automatic suppression on non-TTY output,
NO_COLOR and TERM=dumb.
- Immediate single-key input: a key press changes the screen without Enter, and shortcut loops ignore arrow-key escape sequences.
- Line input for prompts and numeric selection, including prompts printed inside a page and typed in place.
- Forms that draw a page and read several prompts, with the cursor arithmetic handled by the library.
- Editable form fields that open with every initial value already visible, with arrows, Home, End, Delete and Esc cancellation.
- A pure line-editing core in
Ansiform.Line that can be tested without a terminal.
- A step-by-step tutorial and a runnable bookmarks example.
- Unicode-aware display widths for alignment, wrapping, lists and tables.
- Rendering to any
Handle or to a String for embedding and golden tests.
- Per-column table alignment, maximum widths and truncation with an ellipsis.
- Optional ASCII, light, heavy or double box borders for tables and groups.
- A true borderless table mode that keeps aligned columns without border characters or column bands.
- Automatic padding of unequal groups in bordered layouts, so the border stays rectangular.
- A reusable
Theme record for consistent headers, footers, menus and tables.
- Horizontal rules, solid backgrounds, offsets and padding.
- Single-line and multi-line alignment.
- Columns, lists, groups, simple tables and rich tables.
- Paragraph and article wrapping with styled fragments.
- Multi-section pages with amend, replace and redraw support.
- Errors as data: malformed tables return
Nothing instead of throwing.
- Explicit saturating and checked subtraction for non-negative
Number values.
- Small dependency footprint:
ansi-terminal, terminal-size, split, transformers and directory.
Quick start
module Main where
import Data.Char (toLower)
import Ansiform
main :: IO ()
main = withImmediateInput $ do
state <- start examplePage defaultSettings
loop state
loop :: State -> IO ()
loop state = do
key <- readKeyPress
case fmap toLower key of
Just 'b' -> draw bodyPage state >>= loop
Just 'h' -> draw examplePage state >>= loop
Just 'x' -> pure ()
_ -> loop state
examplePage :: Page
examplePage = page [header, body]
bodyPage :: Page
bodyPage = page [body]
header :: Section
header = sectionTopRule 1 (rule '=' (bold black'))
[ printerSolidLineCenter 0 1 blue
[ blockSimple "My Program" (bold white') ] ]
body :: Section
body = sectionBodyRule 1 (rule ':' (bold black'))
[ printerLeft 2 (blockSimple "Hello, world!" styleDefault) ]
Pressing B or H switches pages immediately; X exits. There is no prompt and no Enter.
Build, test and run
cabal build
cabal test
cabal run ansiform-demo
cabal run ansiform-tutorial
ansiform-demo is an interactive gallery. Press the keys shown in the footer; the screen changes immediately, without a prompt or Enter. B returns to the menu, R redraws the current screen and X exits.
ansiform-tutorial is the small bookmarks program from the tutorial.
Formatting, linting and secret scanning are described in the quality guide.
Documentation
- Tutorial: build a small bookmarks program step by step.
- Architecture: module layout, invariants and the pure/IO boundary.
- Content: items, blocks, groups, tables, paragraphs and their builders.
- Styles: colors, formats and reusable text styles.
- Theme: reusable styles for headers, footers, menus and tables.
- Printers: every printer function and its arguments.
- Table formatting: per-column alignment, maximum widths, truncation and borders.
- Sections: grouping printers and reserving minimum line counts.
- Pages and drawing: pages, state and the drawing lifecycle.
- Input: immediate and line input, forms, and the standard interaction loop.
- Platforms: Linux, macOS and Windows behaviour, terminal requirements and known limitations.
- Quality: formatting, linting and secret scanning.
- Ports: an assessment of porting the library to Rust.
- Render: rendering pages, sections and printers to a
Handle or a String.
- Settings: width, spacing and group overflow configuration.
- Numbers: non-negative arithmetic, saturation and checked subtraction.
- Demo: what the executable showcases.
- Naming: name rationale and disambiguation.
- Releasing: Hackage and GitHub publication checklist.
- Roadmap: prioritized feature suggestions.
Design principles
- Immutable values. Every public builder returns a new value; nothing is mutated after creation.
- Pure core. Layout, wrapping and table validation are pure functions. Only the drawing layer performs IO.
- Errors as data. Table builders return
Maybe Table. There are no exceptions in the public API.
- Immediate interaction. The standard interaction is a single key press, handled by
Ansiform.Input without Enter.
- Reusable components. Screens are assembled from shared builders such as
header, footer and rule, keeping behavior and theming consistent.
- Explicit versioning. The package follows the PVP and every release is recorded in CHANGELOG.md.
License
MIT. See LICENSE.