Swiftpack.co - gallinapassus/AttributedText as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by gallinapassus.
gallinapassus/AttributedText 0.1.0
Swift package providing basic constructs to generate attributed text and simple layouts for terminal output.
⭐️ 0
πŸ•“ 3 years ago
.package(url: "https://github.com/gallinapassus/AttributedText.git", from: "0.1.0")

AttributedText

This package provides basic constructs to generate attributed text and simple layouts for terminal output.

Example(s)

Run following example code snippets with Swift's REPL (on a terminal capable of interpreting ANSI escape sequences).

git clone https://github.com/gallinapassus/AttributedText
cd AttributedText
swift run --repl

Copy/paste the example code into REPL to see formatted output.

Example 1 - Formatted text

import AttributedText

typealias Text = AttributedText<DefaultAttributes>
let rgb = Text("R", .bold, .fgColor(.red)) +
    Text("G", .bold, .fgColor(.green)) +
    Text("B", .bold, .fgColor(.blue))
print(rgb.render())
// -> RGB (colored text)

NOTE: Github README.md markdown doesn't properly support coloring of text, hence output examples (below) will be missing colors.

Example 1 output:

RGB

Example 2 - Simple formatted table

typealias Table = AttributedTable<DefaultAttributes>
let source:[[Text]] = [
    [Text("β—ΌοΈŽ", .fgColor(.red)),   Text("red", .bold),   Text("[255,0,0]")],
    [Text("β—ΌοΈŽ", .fgColor(.green)), Text("green", .bold), Text("[0,255,0]")],
    [Text("β—ΌοΈŽ", .fgColor(.blue)),  Text("blue", .bold),  Text("[0,0,255]")],
]
let ascii_table = Table(table: source)
print(ascii_table.render())
// -> Colorful table with default ascii character frame

Example 2 output (colors missing):

+-+-----+---------+
|β—ΌοΈŽ|red  |[255,0,0]|
+-+-----+---------+
|β—ΌοΈŽ|green|[0,255,0]|
+-+-----+---------+
|β—ΌοΈŽ|blue |[0,0,255]|
+-+-----+---------+

Example 3 - Fancy table with title, headers, alignment & word wrapping

let columns:[Table.Column<DefaultAttributes>] = [
    Table.Column(Table.Header("Color", alignment: .bottomCenter, wrapping: .word), alignment: .middleCenter),
    Table.Column(Table.Header("Name", alignment: .bottomLeft)),
    Table.Column("Component values", width: 10, alignment: .middleRight)
]
let title = Table.Title(rgb + " base color component values", alignment: .middleCenter, wrapping: .word)
let fancy_table = Table(table: source,
                        title: title,
                        columns: columns,
                        frameElements: .lightDimmed,
                        frameRenderingOptions: .all)
print(fancy_table.render())
// -> Fancy table with title, headers, alignment & word wrapping

Example 3 output (colors missing):

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    RGB base color    β”‚
β”‚   component values   β”‚
β”œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚     β”‚Component β”‚
β”‚Colorβ”‚Name β”‚values    β”‚
β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β—ΌοΈŽ  β”‚red  β”‚ [255,0,0]β”‚
β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β—ΌοΈŽ  β”‚greenβ”‚ [0,255,0]β”‚
β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β—ΌοΈŽ  β”‚blue β”‚ [0,0,255]β”‚
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example 4 - Document with text & table

typealias Document = AttributedDocument<DefaultAttributes>
let wiki = Text("The RGB color model is an additive color model in which red, green, and blue light are added together in various ways to reproduce a broad array of colors. The name of the model comes from the initials of the three additive primary colors, red, green, and blue.", .dim)
let doc = Document(Text("https://en.wikipedia.org/wiki/RGB_color_model", .fgColor(.blue)))
doc.append(attributed: wiki, width: 64, wrapping: .word)
    .append(fancy_table)
print(doc.render())
// -> Wikipedia intro + fancy table

Example 4 output (colors missing):

https://en.wikipedia.org/wiki/RGB_color_model
The RGB color model is an additive color model in which red,    
green, and blue light are added together in various ways to     
reproduce a broad array of colors. The name of the model comes  
from the initials of the three additive primary colors, red,    
green, and blue.                                                
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    RGB base color    β”‚
β”‚   component values   β”‚
β”œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚     β”‚Component β”‚
β”‚Colorβ”‚Name β”‚values    β”‚
β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β—ΌοΈŽ  β”‚red  β”‚ [255,0,0]β”‚
β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β—ΌοΈŽ  β”‚greenβ”‚ [0,255,0]β”‚
β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β—ΌοΈŽ  β”‚blue β”‚ [0,0,255]β”‚
β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example output on terminal

Versioning

AttributedText package follows semantic versioning scheme https://semver.org/spec/v2.0.0.html. Current version is still at major version 0 (zero), which means "initial development". Anything may change at any time and the public API should not be considered stable.

Features

AttributedText

Conforms to
  • ExpressibleByStringLiteral
  • ExpressibleByArrayLiteral
  • Equatable
  • Collection
  • BidirectionalCollection
  • RangeReplaceableCollection
  • TextOutputStreamable
  • Rendable
Features
  • Coloring text foreground & background
  • Text attributes; bold, dim, italic, underlined, blink, inverse, hidden, strikethrough
  • Combining attributes
    • When two or more AttributedText instances are combined - also the attributes are combined (if possible).

Please note that your terminal app may, or may not, support some of the above mentioned colors & traits.

  • Attribute customisation
    • By default, AttributedText uses it's own internal implementation for generating the attributed output (DefaultAttributes), but it can be completely replaced with custom implementation if needed
    • Custom attribute implementation must conform to following AttributeProtocol
public protocol AttributeProtocol : Equatable {
    static func render(_ attributed:AttributedText<Self>) -> String
}

AttributedTable

Conforms to
  • TextOutputStreamable
  • Rendable
Features
  • Table title
  • Column width / automatic column width calculation
  • Column headers
  • Horizontal & vertical text alignment for columns (or individual cells)
  • Word wrapping options for columns (or individual cells)
    • Ability to customise (=extend) the word wrapping implementation
  • Automatic row numbering
  • Ability to customise the table frame drawing
    • Predefined set of ascii-art table frames (frames can be attributed as well)
    • Options to control which parts of the table frame are drawn
  • Easy initialization from two dimensional array
  • Newline handling
  • Proper attribute handling for multi-line cells
  • Hiding columns
  • Customization
    • Default attributes DefaultAttributes can be replaced with custom implementation. For example DefaultAttributes can be replaced with your favourite Swift attributed text package and implement a specific renderer for it
    • Default renderer DefaultRenderer can be replaced with custom implementation
    • Section header/footer
    • Ability to extend default table frames with custom frame implementations
    • Ability to extend default word wrapping with custom implementations
    • Ability to control individual table cell properties
    • Depends on Swift stdlib only, no Foundation or other package dependencies

AttributedDocument

Conforms to
  • Collection
  • RandomAccessCollection
  • BidirectionalCollection
  • RangeReplaceableCollection
  • TextOutputStreamable
  • Rendable
Features
  • Sections
  • Text
  • Tables

Limitations

  • In general, doesn't support mixing multiple different Attributes within a single document. Workaround: Use multiple documents.
  • AttributedTable, doesn't support merging table cells
  • AttributedTable doesn't support mutation of column width, alignment, wrapping & header after init
  • AttributedDocument doesn't have native constructs to support a layout with mutiple tables side by side or nesting of tables. Rendering multiple tables side by side or nesting is possible, but only for non-attributed content. One has to pre-render each table separately and then place the individually renered tables content into enclosing table's cells.
// Not supported:
// +-+-+-+  +-+-+-+
// |a|b|c|  |1|2|3|
// +-+-+-+  +-+-+-+
// |d|e|f|  |4|5|6|
// +-+-+-+  +-+-+-+
//          |7|8|9|
//          +-+-+-+

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics