SwiftyTextTable - A lightweight Swift library for generating text tables

Overview

SwiftyTextTable

A lightweight Swift library for generating text tables.

Build Status codecov.io Carthage compatible Swift Package Manager compatible CocoaPods Platform OS X + Linux Language Swift 4.0

Example

Swift Language Support

SwiftyTextTable is now Swift 4.0 compatible! The last release to support Swift 3.1 was 0.7.1. The last release to support Swift 2.3 was 0.3.1.

Installation

Carthage (OS X)

You can use Carthage to install SwiftyTextTable by adding it to your Cartfile:

github "scottrhoyt/SwiftyTextTable"

Swift Package Manager (OS X + Linux)

You can use The Swift Package Manager to install SwiftyTextTable by adding the proper description to your Package.swift file:

", dependencies: [ .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.5.0") ] ) ">
import PackageDescription

let package = Package(
    name: "",
    dependencies: [
        .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.5.0")
    ]
)

CocoaPods (OS X)

You can use CocoaPods to install SwiftyTextTable by adding it to your Podfile:

pod 'SwiftyTextTable'

Manual

Simply copy the *.swift files from the Source/SwiftyTextTable directory into your project.

Usage

import SwiftyTextTable

// First create some columns
let foo = TextTableColumn(header: "foo")
let bar = TextTableColumn(header: "bar")
let baz = TextTableColumn(header: "baz")

// Then create a table with the columns
var table = TextTable(columns: [foo, bar, baz])

// Then add some rows
table.addRow([1, 2, 3])
table.addRow([11, 22, 33])

// Then render the table and use
let tableString = table.render()
print(tableString)

/*
+-----+-----+-----+
| foo | bar | baz |
+-----+-----+-----+
| 1   | 2   | 3   |
| 11  | 22  | 33  |
+-----+-----+-----+
*/

// Put a header on the table if you'd like
table.header = "my foo table"
print(table.render())

/*
+-----------------+
| my foo table    |
+-----------------+
| foo | bar | baz |
+-----+-----+-----+
| 1   | 2   | 3   |
| 11  | 22  | 33  |
+-----+-----+-----+
*/

Any CustomStringConvertible can be used for row values.

Creating Tables from Arrays of Objects with TextTableRepresentable

Let's say you have an array of objects that looks this:

enum AnimalType: String, CustomStringConvertible {
    case dog = "Dog"
    case cat = "Cat"
    case gorilla = "Gorilla"

    var description: String {
        return self.rawValue
    }
}

struct Pet {
    let type: AnimalType
    let name: String
    let canHazPizza: Bool
}

let furball = Pet(type: .cat, name: "Furball", canHazPizza: false)
let bestFriend = Pet(type: .dog, name: "Best Friend", canHazPizza: true)
let scary = Pet(type: .gorilla, name: "Scary", canHazPizza: true)
let pets = [furball, bestFriend, scary]

Now you want to print a table containing your pets. You can accomplish this by having Pet conform to TextTableRepresentable:

extension Pet: TextTableRepresentable {
    static var columnHeaders: [String] {
        return ["Name", "Animal", "Can Haz Pizza?"]
    }

    var tableValues: [CustomStringConvertible] {
        return [name, type, canHazPizza ? "yes" : "no"]
    }

    // Optional
    static var tableHeader: String? {
      return "My Pets"
    }
}

You can now print a table of your pets simply:

print(pets.renderTextTable())

/*
+----------------------------------------+
| My Pets                                |
+----------------------------------------+
| Name        | Animal  | Can Haz Pizza? |
+-------------+---------+----------------+
| Furball     | Cat     | no             |
| Best Friend | Dog     | yes            |
| Scary       | Gorilla | yes            |
+-------------+---------+----------------+
*/

Fence Custimization

You can also customize the output of TextTable.render() by using different values for columnFence, rowFence, and cornerFence.

table.columnFence = ":"
table.rowFence = "."
table.cornerFence = "."

print(table.render())

/*
...................
: foo : bar : baz :
...................
: 1   : 2   :     :
: 11  : 22  : 33  :
...................
*/

Row Padding/Truncation

When adding rows, TextTable will automatically pad the rows with empty strings when there are fewer values than columns. TextTable will also disregard all values over the column count.

let foo = TextTableColumn(header: "foo")
let bar = TextTableColumn(header: "bar")
let baz = TextTableColumn(header: "baz")

var table = TextTable(columns: [foo, bar, baz])

table.addRow([1, 2])
table.addRow([11, 22, 33])
table.addRow([111, 222, 333, 444])

let tableString = table.render()
print(tableString)

/*
+-----+-----+-----+
| foo | bar | baz |
+-----+-----+-----+
| 1   | 2   |     |
| 11  | 22  | 33  |
| 111 | 222 | 333 |
+-----+-----+-----+
*/

Console Formatting Support

SwiftyTextTable will recognize many console escape sequences used to format output (e.g. Rainbow) and account for them in constructing the table.

API Reference

Check out the full API reference here.

License

SwiftyTextTable is released under the MIT License.

Comments
  • Improve support for escape sequences to support Rainbow.

    Improve support for escape sequences to support Rainbow.

    Hi, just stumbled across SwiftyTextTable and wanted to use it for a project. Thanks for building it!

    Unfortunately it seems SwiftTextTable is unable to calculate the correct size for a column when trying to apply additional information to the strings via something like onevcat/Rainbow.

    I'm getting this for example when applying the color red to the string foo:

    +--------------+-----+-----+
    | foo | bar | baz |
    +--------------+-----+-----+
    | 1            | 2   | 3   |
    | 11           |     | 33  |
    | 111          | 222 | 333 |
    +--------------+-----+-----+
    

    I'm guessing it's because of this, seeing how color information in the terminal is represented through escape sequences that are counted as additional length in this case. Is there any way one could work around this?

    bug help wanted 
    opened by kiliankoe 26
  • Improved support for escape sequences

    Improved support for escape sequences

    This should resolve #5. I have changed the stripping pattern to account for additional escape sequence. However, I am not aware of all escape sequences, so I might have missed something.

    All test passes and I have tested it with the example provided by @kiliankoe in the issue thread. I have also added two additional stripping test that fail on master.

    I would advise some testing before merging.

    opened by Roslund 4
  • Swift 2.2 and 3.0 compatibility

    Swift 2.2 and 3.0 compatibility

    • Uses Xcode 7.3 for version checking on #if
    • Runs swift test using swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a on OS X
    • ~~Does not add test on Linux because swift-corelibs-foundation is still in Swift 2.2~~
    opened by norio-nomura 3
  • Move tests

    Move tests

    Addresses #3 and should help with realm/SwiftLint#555.

    Note that you'll need to make a new tag in order for these changes to be available to other SPM Packages. :pray:

    opened by jpsim 3
  • Proposed change for Travis CI

    Proposed change for Travis CI

    The following updates have been done to improve readability and convenience of CI builds Travis CI:

    • Use jobs instead of matrix
    • Use stages
    • Give proper names to each job, instead of relying on environment variables
    • Ensure release deploys are only run on master branch
    opened by eneko 2
  •  Pre-compute column width to increase rendering performance

    Pre-compute column width to increase rendering performance

    Summary

    Currently, TextTableColumn.width() method is able to return the column width with complexity O(n). This is, when called, it loops through each value (row) in the column, to compute the width.

    Linear complexity O(n) is not bad per se. However, this method width() is called multiple times per column in the TextTable.render() method.

    Moving the computation of column widths before render() is called improves 2x speed by itself (computation time is reduced in half). However, it imposes a penalty in addRow(), which can still slow down populating large tables.

    To further improve performance removing this bottleneck, a new addRows() method has been introduced, which allows adding all rows to the table as a single operation. This ensures column widths are only computed once, after all values have been added.

    To complement the add row methods, a new method clearRows() has been added. This method will remove all values from the table, which is useful for performance tests and may be also useful for consumers of the package.

    Some statistics

    Given a dataset with 3 columns and 1100+ rows, it took over a minute (72s) to render the table:

    $ swift build
    ...
    $ time swift run
    real	1m12.296s
    user	1m10.930s
    sys	0m1.226s
    

    After the update, it took barely 4 seconds to generate and render the same table:

    $ swift build
    ...
    $ time swift run
    real	0m4.029s
    user	0m3.288s
    sys	0m0.728s
    

    Performance Tests

    Together with additional unit tests for the new addRows() and clearRows() methods, new performance tests have been added with baselines for addRow() and addRows().

    opened by eneko 2
  • Multi-Byte Unicode Characters not counted correctly

    Multi-Byte Unicode Characters not counted correctly

    I found that multi-byte unicode characters are counted incorrectly resulting in wrong column widths:

    +----------------------------------------+-------------+-----------------+
    | FILENAME                               | STATUS      | TIMESTAMP       |
    +----------------------------------------+-------------+-----------------+
    | 234212640FW20_0716_C_FRONT_WHL_096.jpg | ❇️ DELIVERED | 17.06.20, 01:57 |
    | 230257732FW20_0013_C_FRONT_BLL_019.jpg | ❇️ DELIVERED | 22.06.20, 19:54 |
    | 230306780BLAA_038.jpg                  | ❇️ DELIVERED | 16.06.20, 12:00 |
    | 230306780FW20_0290_C_FRONT_BKER.jpg    | ❇️ DELIVERED | 17.06.20, 01:58 |
    +----------------------------------------+-------------+-----------------+
    
    opened by odrobnik 1
  • Swift 4.2 Carthage

    Swift 4.2 Carthage

    I'm trying to use SwiftyTextTable using Carthage on macOS Mojave, with Xcode 10 that uses Swift 4.2, and I'm getting the following error:

    *** Cloning SwiftyTextTable
    *** Checking out SwiftyTextTable at "0.8.2"
    *** xcodebuild output can be found in /var/folders/9t/kjmwgng518vcjnczl_0j9h780000gn/T/carthage-xcodebuild.R3VNUw.log
    *** Downloading SwiftyTextTable.framework binary at "0.8.2"
    ***  Skipped installing SwiftyTextTable.framework binary due to the error:
    	"Incompatible Swift version - framework was built with 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) and the local version is 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1)."
    
        Falling back to building from the source
    *** Building scheme "SwiftyTextTable" in SwiftyTextTable.xcodeproj
    
    opened by arguiot 1
  • Carthage failing on CI builds (Xcode 9.4 required)

    Carthage failing on CI builds (Xcode 9.4 required)

    Just noticed CI builds failing on Travis CI because of Carthage now requiring Xcode 9.4.

    Carthage installed. Upgrading if neccessary.
    carthage (0.25.0) < 0.31.1
    ==> Upgrading 1 outdated package:
    carthage 0.25.0 -> 0.31.1
    carthage: A full installation of Xcode.app 9.4 is required to compile this software.
    Installing just the Command Line Tools is not sufficient.
    Xcode 9.4 cannot be installed on macOS 10.12.
    You must upgrade your version of macOS.
    Error: carthage: An unsatisfied requirement failed this build.
    The command "./scripts/upstall-carthage.sh" failed and exited with 1 during .
    

    I believe this would be fixed by requiring Xcode 9.4 on the .travis.yml file. @scottrhoyt let me know your thoughts, I can submit a PR for that.

    opened by eneko 0
  • Pre-compute column width to increase rendering performance

    Pre-compute column width to increase rendering performance

    Summary

    Currently, TextTableColumn.width() method is able to return the column width with complexity O(n). This is, when called, it loops through each value (row) in the column, to compute the width.

    Linear complexity O(n) is not bad per se. However, this method width() is called multiple times per column in the TextTable.render() method.

    Moving the computation of column widths before render() is called improves 2x speed by itself (computation time is reduced in half). However, it imposes a penalty in addRow(), which can still slow down populating large tables.

    To further improve performance removing this bottleneck, a new addRows() method has been introduced, which allows adding all rows to the table as a single operation. This ensures column widths are only computed once, after all values have been added.

    To complement the add row methods, a new method clearRows() has been added. This method will remove all values from the table, which is useful for performance tests and may be also useful for consumers of the package.

    Some statistics

    Given a dataset with 3 columns and 1100+ rows, it took over a minute (72s) to render the table:

    $ swift build
    ...
    $ time swift run
    real	1m12.296s
    user	1m10.930s
    sys	0m1.226s
    

    After the update, it took barely 4 seconds to generate and render the same table:

    $ swift build
    ...
    $ time swift run
    real	0m4.029s
    user	0m3.288s
    sys	0m0.728s
    

    Performance Tests

    Together with additional unit tests for the new addRows() and clearRows() methods, new performance tests have been added with baselines for addRow() and addRows().

    opened by eneko 0
  • Published CVE's in Swift text table

    Published CVE's in Swift text table

    Our OWASP third party scan tool reported 4 published CVE's in SwiftyTextTable library version 0.9.0 which were listed below. CVE-2015-9251 CVE-2019-11358 CVE-2020-11022 CVE-2020-11023 Is there a plan to resolve this and If there is a plan when we can expect the new version of library.

    opened by Divya-Somasundaram 2
  • Changed accessibility of TextTable.columns to public private(set)

    Changed accessibility of TextTable.columns to public private(set)

    I'm writing an extension that allows JSON output for interaction with other scripts – it required me to open up access to the columns property. I thought I'd send it upstream for those in a similar boat.

    I don't think write access is appropriate, as that is what the addRow/addRows functions are for.

    opened by EricRabil 1
  • Further improve support for escape sequences

    Further improve support for escape sequences

    To address the issues in #5 that @travispaul had, I've updated the striping pattern to be shorter (possibly faster?) and catch bold and underline escape sequences. I've also added three aditional cases for the stripping test

    opened by Roslund 0
Releases(0.9.0)
Owner
Scott Hoyt
Software Engineer @facebook
Scott Hoyt
CommandLineKit - A pure Swift library for creating command-line interfaces

CommandLineKit A pure Swift library for creating command-line interfaces. Note: This project is no longer maintained. It's preserved here for historic

Ben Gollmer 1.1k Dec 1, 2022
A library and CLI Utility to manage NVRAM Stuff, written in Swift.

NVRAMKit A Library and CLI Utility to manage NVRAM Stuff, written in Swift. Library Adding Library to Project Simply add this line to the dependencies

Serena 7 Sep 25, 2022
Swift tool to generate Module Interfaces for Swift projects.

ModuleInterface Swift tool to generate Module Interfaces for Swift projects. What is a Module Interface A Module Interface is what we commonly get usi

Jorge Revuelta 75 Dec 21, 2022
Swift-cli - Example of building command-line tools in Swift

swift-cli Example of building command-line tools in Swift Step 1: Create CLI wit

Noah Gift 2 Jan 17, 2022
Compose beautiful command line interfaces in Swift

Commander is a small Swift framework allowing you to craft beautiful command line interfaces in a composable way. Usage Simple Hello World i

Kyle Fuller 1.5k Dec 29, 2022
Guaka - Smart and beautiful POSIX compliant CLI framework for Swift.

Guaka - Smart and beautiful POSIX compliant CLI framework for Swift. It helps you create modern and familiar CLI apps in the vein of widely used proje

Omar Abdelhafith 1.1k Dec 24, 2022
Progress.swift ⌛ Add beautiful progress bars to your loops.

Progress.swift ⌛ Just wrap the SequenceType in your loop with the Progress SequenceType and you'll automatically get beautiful progress bars. Updating

Justus Kandzi 304 Dec 1, 2022
Straightforward, type-safe argument parsing for Swift

Swift Argument Parser Usage Begin by declaring a type that defines the information that you need to collect from the command line. Decorate each store

Apple 2.9k Jan 7, 2023
SwiftCLI - A powerful framework for developing CLIs in Swift

SwiftCLI A powerful framework for developing CLIs, from the simplest to the most complex, in Swift.

Jake Heiser 793 Jan 4, 2023
SwiftShell - A Swift framework for shell scripting.

Run shell commands | Parse command line arguments | Handle files and directories Swift 5.1 - 5.3 | Swift 4 | Swift 3 | Swift 2 SwiftShell A library fo

Kare Morstol 973 Jan 2, 2023
Shell scripting in Swift

Shwift Shell-scripting in Swift DISCLAIMER: Shwift depends on Swift's incoming concurrency features. As such, it requires a recent Swift toolchain, an

George Lyon 32 Sep 15, 2022
Swift utilities for running commands.

Swift Commands Swift utilities for running commands. The Commands module allows you to take a system command as a string and return the standard outpu

Phil 41 Jan 2, 2023
A CLI too powered by Swift to provision environments using an up.toml manifest file

tuist-up tuist up was originally a Tuist built-in command to provision environments by reading the requirements in a manifest file Setup.swift. Althou

Tuist 5 Mar 31, 2022
Terminal string styling for Swift.

Terminal string styling for Swift. Integration Swift Package Manager (SPM) You can use The Swift Package Manager to install ColorizeSwift by adding it

Michał Tynior 281 Dec 22, 2022
Simple & Elegant Command Line Interfaces in Swift

An elegant pure Swift library for building command line applications. Features Tons of class, but no classes. 100% organic pure value types. Auto gene

hypertalk 52 Nov 9, 2022
✏️Expressive styling on terminal string. (chalk for swift)

Chalk Expressive styling on terminal string. Highlights Expressive API 256/TrueColor support Nest styles Auto downgrading to terminal supported color

Luo Xiu 59 Jun 10, 2022
A starting point to create CLI utilities with swift

cli tuist template A starting point to create CLI utilities with swift Installation Just create a Tuist folder and a Templates folder inside it. Creat

humdrum 6 May 3, 2022
A Tuist Template to quickly create CLI apps in Swift

macOS CLI Template Motivation I'm writing more and more Swift CLI apps these days. And as I solve more problems with this litte tools, I find that I'm

Diego Freniche 21 Dec 28, 2022
A cli program written in swift (with async/await) that removes the unnecessary parts of xcframeworks.

xctrim A cli program written in swift (with async/await) that removes the unnecessary parts of xcframeworks. Usecase Say you downloaded firebase sdk a

Mustafa Yusuf 32 Jul 18, 2022