Swift package for easily rendering text tables. Inspired by the Python tabulate library.

Overview

TextTable

Swift 5.0 License MIT License MIT Build Status

Easily print textual tables in Swift. Inspired by the Python tabulate library.

Upcoming Changes

See details on an upcoming change.

Features

  • Easily generate textual tables from collections of any type
  • Auto-calculates column width
  • Custom width for individual columns
  • Align individual columns
  • Supports per-column Formatters
  • Multiple table output styles including Markdown, Emacs, HTML, Latex etc...
  • Extensible table styles allow you to easily create your own table style
  • Column-specific truncation modes (truncate head or tail of column content or optionally fail if content overflows).

Requirements

This package was written for and tested with the following version of Swift:

Apple Swift version 5.0

Usage

Use the Swift Package Manager to install TextTable as a dependency of your project.

dependencies: [
    .package(
        url: "https://github.com/cfilipov/TextTable",
        .branch("master"))
]

First, import TextTable:

import TextTable

Throughout the examples, the following data structure will be used:

struct Person {
    let name: String
    let age: Int
    let birhtday: Date
}

Let's say we have a collection of Person we wish to display as a table.

let data = [
	Person(name: "Alice", age: 42, birhtday: Date()),
	Person(name: "Bob", age: 22, birhtday: Date()),
	Person(name: "Eve", age: 142, birhtday: Date())
]

Configure a TextTable Instance

Configure a TextTable instance for the type you wish to print as a table. The minimum configuration will require a mapping of values to columns for your type.

let table = TextTable<Person> {
    [Column("Name" <- $0.name),
     Column("Age" <- $0.age),
     Column("Birthday" <- $0.birhtday)]
}

Alternate Syntax

The <- operator is just syntactic sugar. If you don't want to use the operator, you can use labeled arguments instead.

let table = TextTable<Person> {
    [Column(title: "Name", value: $0.name),
     Column(title: "Age", value: $0.age),
     Column(title: "Birthday", value: $0.birhtday)]
}

Printing a Table

Simply call the print() method, passing in a collection of Person.

table.print(data)
Name  Age Birthday
----- --- -------------------------
Alice 42  2016-08-13 19:21:54 +0000
Bob   22  2016-08-13 19:21:54 +0000
Eve   142 2016-08-13 19:21:54 +0000

Getting a String

You can also just get the rendered table as a string by calling the string(for:) method.

let s = table.string(for: data)

Customize Table Style

You can optionally specify a table style using the style: argument.

table.print(data, style: Style.psql)
+-------+-----+---------------------------+
| Name  | Age | Birthday                  |
+-------+-----+---------------------------+
| Alice | 42  | 2016-08-13 08:12:58 +0000 |
| Bob   | 22  | 2016-08-13 08:12:58 +0000 |
| Eve   | 142 | 2016-08-13 08:12:58 +0000 |
+-------+-----+---------------------------+

The style can also be specified when using the string(for:) method.

let s = table.string(for: data, style: Style.psql)

For a full list of supported styles see Supported Styles below.

Column-Specific Formatters

You can specify a Formatter on a per-column basis. In this example a DateFormatter is used to customize the display of the Birthday column.

let df = DateFormatter()
dateFormatter.dateStyle = .medium

let table = TextTable<Person> {
    [Column("Name" <- $0.name),
     Column("Age" <- $0.age),
     Column("Birthday" <- $0.birhtday, formatter: df)]
}

table.print(data, style: Style.psql)
+-------+-----+--------------+
| Name  | Age | Birthday     |
+-------+-----+--------------+
| Alice | 42  | Aug 13, 2016 |
| Bob   | 22  | Aug 13, 2016 |
| Eve   | 142 | Aug 13, 2016 |
+-------+-----+--------------+

Column Width

By default TextTable will calculate the necessary width for each column. You can also explictely set the width with the width: argument.

let table = TextTable<Person> {
    [Column("Name" <- $0.name, width: 10),
     Column("Age" <- $0.age, width: 10)]
}

table.print(data, style: Style.psql)
+------------+------------+
| Name       | Age        |
+------------+------------+
| Alice      | 42         |
| Bob        | 22         |
| Eve        | 142        |
+------------+------------+

Note on Padding

Some table styles may include padding to the left and/or right of the content, the width argument does not effect include this padding.

Truncation

Truncate Tail

By default, if a width is specified and the contents of the column are wider than the width, the text will be truncated at the tail (.tail truncation mode).

let table = TextTable<Person> {
	[Column("Name" <- $0.name, width: 4), // defaults to truncation: .tail
	 Column("Age" <- $0.age)]
}

table.print(data, style: testStyle)
+------+-----+
| Name | Age |
+------+-----+
| Ali… | 42  |
| Bob  | 22  |
| Eve  | 142 |
+------+-----+

Truncate Head

You can also truncate at the head of the text string by specifying .head for the truncation: argument. If no width argument is present, the truncation argument has no effect.

let table = TextTable<Person> {
	[Column("Name" <- $0.name, width: 4, truncate: .head),
	 Column("Age" <- $0.age)]
}

table.print(data, style: testStyle)
+------+-----+
| Name | Age |
+------+-----+
| …ice | 42  |
| Bob  | 22  |
| Eve  | 142 |
+------+-----+

Truncate Error

If you prefer to have an fatal error triggered when the contents of a column do not fit the specified width you can specify the .error truncation mode.

let table = TextTable<Person> {
	[Column("Name" <- $0.name, width: 4, truncate: .error),
	 Column("Age" <- $0.age)]
}

table.print(data, style: testStyle)

// fatal error: Truncation error

Column Alignment

By default, all columns will be left-aligned. You can set the alignment on each column individually.

let table = TextTable<Person> {
    [Column("Name" <- $0.name), // default: .left
     Column("Age" <- $0.age, align: .right)]
}

table.print(data, style: Style.psql)
+-------+-----+
| Name  | Age |
+-------+-----+
| Alice |  42 |
| Bob   |  22 |
| Eve   | 142 |
+-------+-----+

Performance Characteristics

By default TextTable will calculate the necessary width for each column that does not specify an explicit width using the width: column argument. This calculation is accomplished by iterating over each row of the table twice: the first time to calculate the max width, the second time to actually render the table. The overhead of this calculation may not be appropriate for very large tables. If you wish to avoid this calculation you must specify the width for every column.

In the example below table1 will incur the overhead of the width calculation because one of the columns does not have an explicit width. On the other hand, table2 will not incur the overhead because all columns have an explicit width.

// This will still result in extra calculations
let table1 = TextTable<Person> {
    [Column("Name" <- $0.name),
     Column("Age" <- $0.age, width: 10)]
}
// This will skip the width calculations
let table2 = TextTable<Person> {
    [Column("Name" <- $0.name, width: 9),
     Column("Age" <- $0.age, width: 10)]
}

Supported Styles

TextTable supports most of the styles as tabulate.

Plain

table.print(data, style: Style.plain)
Name  Age Birthday
Alice  42  8/13/16
Bob    22  8/13/16
Eve   142  8/13/16

Simple

simple is the default Style. It corresponds to simple_tables in Pandoc Markdown extensions.

table.print(data) // or:
table.print(data, style: Style.simple)
Name  Age Birthday
----- --- --------
Alice  42  8/13/16
Bob    22  8/13/16
Eve   142  8/13/16

Grid

grid follows the conventions of Emacs’ table.el package. It corresponds to grid_tables in Pandoc Markdown extensions.

table.print(data, style: Style.grid)
+-------+-----+----------+
| Name  | Age | Birthday |
+=======+=====+==========+
| Alice |  42 |  8/13/16 |
+-------+-----+----------+
| Bob   |  22 |  8/13/16 |
+-------+-----+----------+
| Eve   | 142 |  8/13/16 |
+-------+-----+----------+

FancyGrid

table.print(data, style: Style.fancyGrid)
╒═══════╤═════╤══════════╕
│ Name  │ Age │ Birthday │
╞═══════╪═════╪══════════╡
│ Alice │  42 │  8/13/16 │
├───────┼─────┼──────────┤
│ Bob   │  22 │  8/13/16 │
├───────┼─────┼──────────┤
│ Eve   │ 142 │  8/13/16 │
╘═══════╧═════╧══════════╛

Psql

table.print(data, style: Style.psql)
+-------+-----+----------+
| Name  | Age | Birthday |
+-------+-----+----------+
| Alice |  42 |  8/13/16 |
| Bob   |  22 |  8/13/16 |
| Eve   | 142 |  8/13/16 |
+-------+-----+----------+

Pipe

pipe follows the conventions of PHP Markdown Extra extension. It corresponds to pipe_tables in Pandoc. This style uses colons to indicate column alignment.

table.print(data, style: Style.pipe)
| Name  | Age | Birthday |
|:------|----:|---------:|
| Alice |  42 |  8/13/16 |
| Bob   |  22 |  8/13/16 |
| Eve   | 142 |  8/13/16 |

Org

org follows the conventions of Emacs org-mode.

table.print(data, style: Style.org)
| Name  | Age | Birthday |
|-------+-----+----------|
| Alice |  42 |  8/13/16 |
| Bob   |  22 |  8/13/16 |
| Eve   | 142 |  8/13/16 |

Rst

rst follows the conventions of simple table of the reStructuredText Style.

table.print(data, style: Style.rst)
===== === ========
Name  Age Birthday
===== === ========
Alice  42  8/13/16
Bob    22  8/13/16
Eve   142  8/13/16
===== === ========

Html

html produces HTML table markup.

table.print(data, style: Style.html)
Name Age Birthday Alice 42 8/14/16 Bob 22 8/14/16 Eve 142 8/14/16 ">
Name Age Birthday
Alice 42 8/14/16
Bob 22 8/14/16
Eve 142 8/14/16

Latex

latex produces a tabular environment for Latex.

table.print(data, style: Style.latex)
\begin{tabular}{lll}
\hline
 Name & Age & Birthday \\
\hline
 Alice & 42 & 8/13/16 \\
 Bob & 22 & 8/13/16 \\
 Eve & 142 & 8/13/16 \\
\hline
\end{tabular}

Custom Styles

You can create a custom table style by conforming to the TextTableStyle protocol.

enum MyCustomStyle: TextTableStyle {
    // implement methods from TextTableStyle...
}

extension Style {
    static let custom = MyCustomStyle.self
}

table.print(data, style: Style.custom)

Changes

A list of changes can be found in the CHANGELOG.

Alternatives

Other Swift libraries that serve a similar purpose.

License

MIT License

Copyright (c) 2016 Cristian Filipov

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

You might also like...
BaseTableViewOriginal - Base TableView Original With Swift

BaseTableViewOriginal Example To run the example project, clone the repo, and ru

ListViewSwiftUI - A project for creating a vertical list using the Swift UI.This project include topic,ListView to show list of movies,Tabbar SwiftyTextTable - A lightweight Swift library for generating text tables
SwiftyTextTable - A lightweight Swift library for generating text tables

SwiftyTextTable A lightweight Swift library for generating text tables. Swift Language Support SwiftyTextTable is now Swift 4.0 compatible! The last r

A lightweight library for generating text tables.
A lightweight library for generating text tables.

SwiftyTextTable A lightweight Swift library for generating text tables. Swift Language Support SwiftyTextTable is now Swift 4.0 compatible! The last r

A μframework of extensions for SequenceType in Swift 2.0, inspired by Python's itertools, Haskell's standard library, and other things.

SwiftSequence Full reference here. (If you're looking for data structures in Swift, those have been moved to here) SwiftSequence is a lightweight fram

 Microtonal Tuning Tables for AudioKit
Microtonal Tuning Tables for AudioKit

Microtonal Tuning Tables for AudioKit These tuning tables were developed by Marcus Hobbs and used in the AudioKit Synth One iOS app. Installation via

A python library to run metal compute kernels on MacOS 12

metalcompute for Python A python library to run metal compute kernels on MacOS Usage Example execution from M1-based Mac running MacOS 12.0: ./build

Rendering Markdown text natively in SwiftUI.
Rendering Markdown text natively in SwiftUI.

MarkdownView MarkdownView is a Swift Package for rendering Markdown text natively in SwiftUI. Thanks to apple/swift-markdown, it can fully compliant w

Python VM written in Swift

Violet Violet is one of those Swift - Python interop thingies, except that this time we implement the whole language from scratch. Name comes from V

Forblaze - A Python Mac Steganography Payload Generator

Forblaze - A Python Mac Steganography Payload Generator Author: AsaurusRex Disclaimer DO NOT use this project for purposes other than legitimate red t

iOS sandboxed terminal with Python, Lua and Clang

LibTerm LibTerm is a terminal for iOS with Python 3.7 and Lua 5.3. Supports iOS 13 dark mode and multi window. Features The app supports most of OpenT

DGQR - A lightweight, pure-Swift library for rendering qr
DGQR - A lightweight, pure-Swift library for rendering qr

DGQR DGQR is a lightweight, pure-Swift library for rendering qr. It provides you

StyledTextKit is a declarative attributed string library for fast rendering and easy string building.
StyledTextKit is a declarative attributed string library for fast rendering and easy string building.

StyledTextKit is a declarative attributed string library for fast rendering and easy string building. It serves as a simple replacement to NSAttribute

Custom emoji rendering library for iOS apps with support for GIF & still images
Custom emoji rendering library for iOS apps with support for GIF & still images

Custom emoji rendering library for iOS apps with support for GIF & still images - plug-in extension for UITextView - performance, cache ✅ - Made with 💘 by @GetStream

SwiftUI-Text-Animation-Library - Text animation library for SwiftUI
SwiftUI-Text-Animation-Library - Text animation library for SwiftUI

⚠️ This repository is under construction. SwiftUI Text Animation Library Make yo

Blazing fast Markdown / CommonMark rendering in Swift, built upon cmark.
Blazing fast Markdown / CommonMark rendering in Swift, built upon cmark.

Down Blazing fast Markdown (CommonMark) rendering in Swift, built upon cmark v0.29.0. Is your app using it? Let us know! If you're looking for iwasrob

AttributedText is a Swift µpackage that provides NSAttributedString rendering in SwiftUI by wrapping either an NSTextView or a UITextView depending on the platform.
AttributedText is a Swift µpackage that provides NSAttributedString rendering in SwiftUI by wrapping either an NSTextView or a UITextView depending on the platform.

AttributedText AttributedText is a Swift µpackage that provides NSAttributedString rendering in SwiftUI by wrapping either an NSTextView or a UITextVi

PLHKit: A Swift DSL for Rendering and creating PDF Files.
PLHKit: A Swift DSL for Rendering and creating PDF Files.

PLHKit PLH is a tribute to Portsaid Light House, Port Said Lighthouse was the first building in the world created with reinforced concrete. 🌊 PLHKit

iOS utility classes for asynchronous rendering and display.

YYAsyncLayer iOS utility classes for asynchronous rendering and display. (It was used by YYText) Simple Usage @interface YYLabel : UIView @property NS

Comments
  • Upcoming Changes

    Upcoming Changes

    The API of this lib has seen several major changes. But it has been converging on what I think resembles a good API.

    New Text Table Creation

    As of v1.0.0-alpha.4 this is how you create a text table:

    let table = TextTable<Person> {
        [Column("Name" <- $0.name),
         Column("Age" <- $0.age),
         Column("Birthday" <- $0.birhtday)]
    }
    

    This has one major disadvantage:

    The closure that maps the type to a column value is intertwined with the rest of the column definition. You can't get the column definition without calling the closure, and you can't call the closure unless you pass in a value. This is problematic when you need column information up front, before the first row is even processed. The callback ends up calling the closure using the first row multiple times just to get the column definition.

    I propose the next version will have the following API instead:

    let table: TextTable<Person> = [
        { $0.name } <- Column("Name"),
        { $0.country } <- Column("Country"),
        { $0.visited } <- Column("Last Visit")
    ]
    

    Since the example above didn't customize the columns in any way, the following is also valid:

    let table: TextTable<Person> = [
        { $0.name } <- "Name",
        { $0.country } <- "Country",
        { $0.visited } <- "Last Visit"
    ]
    

    The goal is that this library will have good-enough defaults that for most cases one wouldn't be compelled to customize each column.

    The <- operator is just syntactic sugar that allows us to keep the property mapping visually close to the column name so it reads better. The following is equivalent to the previous two examples:

    let table: TextTable<Person> = [
        Column("Name", valueMapping: { $0.name }),
        Column("Country", valueMapping: { $0.country }),
        Column("Last Visit", valueMapping: { $0.visited })
    ]
    

    Note the differences to the current API:

    1. TextTable<T> now conforms to ExpressibleByArrayLiteral. Instead of passing a closure on the init method of TextTable, you are now passing an array literal of columns.
    2. The value mapping for the column is defined as an individual closure for each column instead of a single closure for all columns.

    Customizing the columns works similar to the current version:

    let table: TextTable<Person> = [
        { $0.name } <- Column("Name", align: .left),
        { $0.country } <- Column("Country", align: .center, width: 12, truncate: .head),
        { $0.visited } <- Column("Last Visit", align: .right, formatter: df)
    ]
    

    String Constructor Instead of String Method

    Another change to consider: Extending String with an init for TextTable instead of using a string(for:) method.

    let s = String(table: table)
    

    Instead of

    let s = table.string(for: data)
    

    Stream Print

    TextTable tries to be memory efficient. It will not copy the contents of your collection, instead it will call back to your collection whenever it needs a value.

    Currently the print method on table just creates a string using the aforementioned API and just passes it to Swift.print. The next version will instead stream the contents of the table to Swift.print roughly line-by-line as the table is generated.

    Conformance to Sequence Type

    TextTable will actually conform to swift's Collection (or maybe just provide a Sequence). This will let one lazily pull the string parts of the rendered table.

    enhancement question 
    opened by cfilipov 1
  • Support colors in table cells

    Support colors in table cells

    Hi,

    I would like to use https://github.com/onevcat/Rainbow to colorize cells in a TextTable.

    let table = TextTable<Attributes> {
        [   
            Column(title: "Country", value: $0.country!.blue), 
            Column(title: "County", value: $0.county!.red),
        ]   
    }   
    table.print(result, style: Style.psql)
    

    This result in a table where the length of the cell data in https://github.com/cfilipov/TextTable/blob/master/Sources/TextTable/TextTable.swift#L237 should only count the visible characters. The escape sequences used for colors should not be counted here:

    +----------------------------+--------------------------------+
    | Country                    | County                         |
    +----------------------------+--------------------------------+
    | Baden-Württemberg | SK Karlsruhe          |
    | Baden-Württemberg | SK Ulm                |
    

    (The colors are missing...)

    Is there any way this can already be achieved or implemented?

    Greetings Joachim

    opened by jlusiardi 0
  • Cocoapods support

    Cocoapods support

    I've been keeping an eye on this repo for ages, because it's a nice fit for some console debug output I need for histograms. Today was the day I decided to put it in action, then I realised there's no pod.

    I'm reading up on Swift's packager manager now, but it's so far not as straight forward (from my perspective) as Cocoapods, so it's a hindrance. Being able to just add another line to my Podfile would be a plus.

    That aside, loving the design of this lib!

    enhancement 
    opened by sobri909 2
  • Proposed API breaking changes

    Proposed API breaking changes

    This proposal supersedes #1, which was tentatively abandoned. This proposal is a breaking API change predicated on the approval of improved key paths in swift SE-0161.

    New Text Table Creation

    I propose a new API for constructing a TextTable instance. In particular, the way column definitions are mapped to values. Column/value mapping will be defined via a dictionary of key paths to columns.

    Current API

    The current API uses an initializer that takes a closure which is expected to return an array of column definitions given an instance of some row type Person.

    let table = TextTable<Person> {
        [Column("Name" <- $0.name),
         Column("Age" <- $0.age),
         Column("Birthday" <- $0.birthday)]
    }
    

    This has a few disadvantages:

    1. We can't get the column definition without a value passed to the closure, so a dummy value (the instance for the 0th row) is passed to get the column names.
    2. When computing column widths we actually want to traverse all the values of one column at a time, but we are forced to get the whole row each time.
    3. The column definition itself loses the type information of the value, storing it in an Any.

    New API

    With the new API, TextTable will conform to ExpressibleByDictionaryLiteral. A TextTable<T> will be created by using a dictionary literal of [PartialKeyPath<T>: Column].

    Questions

    1. Should Column be Column<T>?
    2. Could/should we use KeyPath<T, V> instead?
    let table: TextTable<Person> = [
        .name: "Name",
        .country: "Country",
        .visited: "Last Visit"
    ]
    

    The above snippet of code is just short hand for the following (Column will conform to ExpressibleByStringLiteral, so Column does not have to be explicitly constructed):

    let table: TextTable<Person> = [
        .name: Column("Name"),
        .country: Column("Country"),
        .visited: Column("Last Visit")
    ]
    

    The above snippet is also short hand for the following code. This example illustrates the default values that are used when you leave out the optional arguments. Typically you would only provide arguments where you want to customize the specific column.

    let table: TextTable<Person> = [
        .name: Column("Name", width: .auto, align: .auto, truncate: .tail, formatter: nil),
        .country: Column("Country", width: .auto, align: .auto, truncate: .tail, formatter: nil),
        .visited: Column("Last Visit", width: .auto, align: .auto, truncate: .tail, formatter: nil)
    ]
    

    You would never type this out, but for illustration purposes here is an even more explicit version. Once again, this is equivalent to all the previous examples:

    let table: TextTable<Person> = [
        #keyPath(Person, .name): Column("Name", width: .auto, align: .auto, truncate: .tail, formatter: nil),
        #keyPath(Person, .country): Column("Country", width: .auto, align: .auto, truncate: .tail, formatter: nil),
        #keyPath(Person, .visited): Column("Last Visit", width: .auto, align: .auto, truncate: .tail, formatter: nil)
    ]
    

    String Constructor Instead of String Method

    Another change to consider: Extending String with an init for TextTable instead of using a string(for:) method.

    let s = String(table: table)
    

    Instead of

    let s = table.string(for: data)
    

    Stream Print

    TextTable tries to be memory efficient. It will not copy the contents of your collection, instead it will call back to your collection whenever it needs a value.

    Currently the print method on table just creates a string using the aforementioned API and just passes it to Swift.print. The next version will instead stream the contents of the table to Swift.print roughly line-by-line as the table is generated.

    Conformance to Sequence Type

    TextTable will actually conform to swift's Collection (or maybe just provide a Sequence). This will let one lazily pull the string parts of the rendered table.

    enhancement question 
    opened by cfilipov 0
Releases(v1.0.0-alpha.4)
  • v1.0.0-alpha.4(Aug 17, 2016)

    What's New

    • Update for Xcode 8 beta 6 (Apple Swift version 3.0 (swiftlang-800.0.43.6 clang-800.0.38))
    • Travis-CI integration

    SPM Dependency Snippet

    .Package(url: "https://github.com/cfilipov/TextTable", Version(1, 0, 0, prereleaseIdentifiers: ["alpha", "4"]))
    
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-alpha.3(Aug 17, 2016)

    What's New

    • This release contains breaking changes to the API. This should hopefully be the last major breaking change to the API for a long time.
    • TextTable<T> construction closure now takes an instance of T instead of a Config<T>. Config<T> has been removed completely. Instead of calling column(...) on a Config<T> in the closure, you now return an array of Column instances. See example transition below for details.
    • Fixed: Missing/broken tests.
    • Fixed: Latex tabular environment contains incorrect alignments.
    • Fixed: Handle optional values in mapping.
    • Fixed: FancyGrid using pipe symbol instead of unicode drawing character for header separator.
    • All columns are now left-aligned by default (instead of right-aligning the first column by default).
    • TextTableFormatter has been renamed to TextTableStyle to avoid confusion with the Foundation Formatters class. All references to the word "format" when referring to the type of table rendered have bee changed to "style".
    • The TextTableStyle protocol (formerly TextTableFormatter) is now simplified. All methods in TextTableStyle are now static, no state is maintained in TextTableStyle. The methods have also been consolidated (row instead of beginRow, endRow, content, beginColumn, etc...).
    • TextTable<T> and all the internal types are now value types instead of classes.
    • All built-in styles are case-less enums so they cannot be accidentally instantiated.

    Known Issues

    • Very little effort has but put into performance optimizations. String utilities in particular.
    • It should be possible to create columns without headers, but this hasn't been tested and likely doesn't work yet.

    Transitioning

    Before:

    let table = TextTable<Person> { t in
        t.column("Name") { $0.name }
        t.column("Age") { $0.age }
        t.column("Birthday") { $0.birhtday }
    }
    

    After:

    let table = TextTable<Person> {
        [Column("Name" <- $0.name),
         Column("Age" <- $0.age),
         Column("Birthday" <- $0.birhtday)]
    }
    

    SPM Dependency Snippet

    .Package(url: "https://github.com/cfilipov/TextTable", Version(1, 0, 0, prereleaseIdentifiers: ["alpha", "3"]))
    
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-alpha.2(Aug 15, 2016)

    What's New

    • Column truncation support. There is now an optional truncate: argument to width.
    • Added some documentation.

    Known Issues

    • Very little effort has but put into performance optimizations.
    • It should be possible to create columns without headers, but this hasn't been tested and likely doesn't work yet.

    SPM Dependency Snippet

    .Package(url: "https://github.com/cfilipov/TextTable", Version(1, 0, 0, prereleaseIdentifiers: ["alpha", "2"]))
    
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-alpha.1(Aug 13, 2016)

    What's New

    • Support for center alignment.
    • If all columns have explicit width, then width calculations are skipped.
    • Escape strings in certain formats (HTML & Latex, for example).
    • Fixed: TextTable config persists calculated column widths. This results in widths getting stuck from the first call to print or string(for:).

    Known Issues

    • Very little effort has but put into performance optimizations.
    • It should be possible to create columns without headers, but this hasn't been tested and likely doesn't work yet.

    SPM Dependency Snippet

    .Package(url: "https://github.com/cfilipov/TextTable", Version(1, 0, 0, prereleaseIdentifiers: ["alpha", "1"]))
    
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-alpha.0(Aug 13, 2016)

    What's New

    • Breaking change: completely re-written API. No more conforming to a protocol, instead a TextTable class is used in similar to NSFormatter. This offers much more flexibility.
    • Many more output formats. Similar to what you get from Python's tabulate lib.

    Known Issues

    • No attempt at optimizing performance has been made yet. Even when widths are provided, an expensive calculation is still performed.
    • No escaping is being done. None of the formatters even attempt to sanitize the input strings.
    • Center alignment not supported. This will result in a fatalError().
    • It should be possible to create columns without headers, but this hasn't been tested and likely doesn't work yet.

    SPM Dependency Snippet

    .Package(url: "https://github.com/cfilipov/TextTable", Version(1, 0, 0, prereleaseIdentifiers: ["alpha", "0"]))
    
    Source code(tar.gz)
    Source code(zip)
Owner
Cristian Filipov
Cristian Filipov
APDynamicGrid is a SwiftUI package that helps you create consistent and animatable grids.

APDynamicGrid Overview APDynamicGrid is a SwiftUI package that helps you create consistent and animatable grids. The DynamicGrid View preserves the sa

Antonio Pantaleo 29 Jul 4, 2022
A Swift library for swipeable table cells

BWSwipeRevealCell Using the library **Note: Use version 1.0.1 for Swift 2.3 support and version 2.0.0 or higher for Swift 3 support ** There are two m

Kyle Newsome 67 May 11, 2022
VTMagic is a page container library for iOS.

VTMagic VTMagic is a page container library for iOS, you can custom every page controller by different identifier if you need. It's so easy to use!(中文

Victor Tian 1.8k Dec 28, 2022
Objective-C library for drag-n-drop of UITableViewCells in a navigation hierarchy of view controllers.

ios-dragable-table-cells Support for drag-n-drop of UITableViewCells in a navigation hierarchy of view controllers. You drag cells by tapping and hold

Anders Borum 49 Aug 23, 2022
Simple static table views for iOS in Swift.

Simple static table views for iOS in Swift. Static's goal is to separate model data from presentation. Rows and Sections are your “view models” for yo

Venmo 1.3k Nov 19, 2022
A simple way to create a UITableView for settings in Swift.

QuickTableViewController A simple way to create a table view for settings, including: Table view cells with UISwitch Table view cells with center alig

Cheng-Yao Lin 525 Dec 20, 2022
A pixel perfect replacement for UITableView section index, written in Swift

MYTableViewIndex MYTableViewIndex is a re-implementation of UITableView section index. This control is usually seen in apps displaying contacts, track

Yury 520 Oct 27, 2022
A no-nonsense way to write cleaner UITableViewDelegate and UITableViewDataSource in Swift.

CascadingTableDelegate A no-nonsense way to write cleaner UITableViewDelegate and UITableViewDataSource. Why is this library made? In common iOS devel

Ricardo Pramana Suranta 920 Dec 14, 2022
Swipeable UITableViewCell/UICollectionViewCell based on the stock Mail.app, implemented in Swift.

SwipeCellKit Swipeable UITableViewCell/UICollectionViewCell based on the stock Mail.app, implemented in Swift. About A swipeable UITableViewCell or UI

null 6k Jan 7, 2023
TableViews - Emoji Table View For iOS With Swift

TableViews Hello! This is EmojiTableView. Let me introduce you my first app when

null 0 Jan 2, 2022