• Stars
    star
    321
  • Rank 130,752 (Top 3 %)
  • Language
    Swift
  • License
    MIT License
  • Created over 4 years ago
  • Updated 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Pretty print for Swift.

SwiftPrettyPrint

Test CocoaPods Carthage Compatible SPM Compatible License Twitter

Logo

SwiftPrettyPrint gives Human-readable outputs than print(), debugPrint() and dump() in Swift standard library.

Screenshot

Features ๐Ÿš€

  • Style
    • Single-line
    • Multi-line
  • Integration
    • LLDB
    • Terminal
    • Combine
    • RxSwift
  • Package Manager
    • Swift Package Manager
    • CocoaPods
    • Carthage
  • OS Support
    • Apple platforms
    • Linux
    • Windows
  • SwiftUI Property-wrapper
    • @AppStorage
    • @Binding
    • @Environment
    • @EnvironmentObject
    • @FetchRequest (Property-wrapper name only)
    • @FocusedBinding
    • @FocusedState (Property-wrapper name only)
    • @FocusedValue
    • @GestureState
    • @Namespace
    • @ObservedObject
    • @Published
    • @ScaledMetric
    • @SceneStorage (Support types are limited only URL, Int, Double, String and Bool)
    • @State
    • @StateObject
    • @UIApplicationDelegateAdaptor (Property-wrapper name only)
    • @NSApplicationDelegateAdaptor (Property-wrapper name only)

Table of Contents ๐Ÿ“–

Motivation ๐Ÿ’ช

The print(), debugPrint() and dump() are implemented in standard library of Swift. But outputs of these functions are difficult to read sometimes.

For example, there are following types and a value:

enum Enum {
    case foo(Int)
}

struct ID {
    let id: Int
}

struct Struct {
    var array: [Int?]
    var dictionary: [String: Int]
    var tuple: (Int, string: String)
    var `enum`: Enum
    var id: ID
}

let value = Struct(array: [1, 2, nil],
                   dictionary: ["one": 1, "two": 2],
                   tuple: (1, string: "string"),
                   enum: .foo(42),
                   id: ID(id: 7))

Use Standard library of Swift

When you use the standard library, you get the following results.

print(value)
// Struct(array: [Optional(1), Optional(2), nil], dictionary: ["one": 1, "two": 2], tuple: (1, string: "string"), enum: SwiftPrettyPrintExample.Enum.foo(42), id: SwiftPrettyPrintExample.ID(id: 7))

debugPrint(value)
// SwiftPrettyPrintExample.Struct(array: [Optional(1), Optional(2), nil], dictionary: ["one": 1, "two": 2], tuple: (1, string: "string"), enum: SwiftPrettyPrintExample.Enum.foo(42), id: SwiftPrettyPrintExample.ID(id: 7))

dump(value)
// โ–ฟ SwiftPrettyPrintExample.Struct
//   โ–ฟ array: 3 elements
//     โ–ฟ Optional(1)
//       - some: 1
//     โ–ฟ Optional(2)
//       - some: 2
//     - nil
//   โ–ฟ dictionary: 2 key/value pairs
//     โ–ฟ (2 elements)
//       - key: "one"
//       - value: 1
//     โ–ฟ (2 elements)
//       - key: "two"
//       - value: 2
//   โ–ฟ tuple: (2 elements)
//     - .0: 1
//     - string: "string"
//   โ–ฟ enum: SwiftPrettyPrintExample.Enum.foo
//     - foo: 42
//   โ–ฟ id: SwiftPrettyPrintExample.ID
//     - id: 7

These outputs are enough informations for debugging, but not human-readable outputs.

Use SwiftPrettyPrint

With the SwiftPrittyPrint, it looks like this:

Pretty.print(value)
// Struct(array: [1, 2, nil], dictionary: ["one": 1, "two": 2], tuple: (1, string: "string"), enum: .foo(42), id: 7)

Pretty.prettyPrint(value)
// Struct(
//     array: [
//         1,
//         2,
//         nil
//     ],
//     dictionary: [
//         "one": 1,
//         "two": 2
//     ],
//     tuple: (
//         1,
//         string: "string"
//     ),
//     enum: .foo(42),
//     id: 7
// )

Of course, we also can use the SwiftPrettyPrint with LLDB. (By using LLDB integration, you can use it with shorter keywords such as _p and _pp)

(lldb) e Pretty.prettyPrint(value)
Struct(
    array: [
        1,
        2,
        nil
    ],
    dictionary: [
        "one": 1,
        "two": 2
    ],
    tuple: (
        1,
        string: "string"
    ),
    enum: .foo(42),
    id: 7
)

API

SwiftPrettyPrint has four basic functions as follows:

  • print(label: String?, _ targets: Any..., separator: String, option: Pretty.Option)
    • print in one-line.
  • prettyPrint(label: String?, _ targets: Any..., separator: String, option: Pretty.Option)
    • print in multiline.
  • printDebug(label: String?, _ targets: Any..., separator: String, option: Pretty.Option)
    • print in one-line with type-information.
  • prettyPrintDebug(label: String?, _ targets: Any..., separator: String, option: Pretty.Option)
    • print in multiline with type-information.

The only required argument is targets, it can usually be described as follows.

let array: [URL?] = [
    URL(string: "https://github.com/YusukeHosonuma/SwiftPrettyPrint"),
    nil
]

Pretty.print(array)
// => [https://github.com/YusukeHosonuma/SwiftPrettyPrint, nil]

Pretty.prettyPrint(array)
// =>
// [
//     https://github.com/YusukeHosonuma/SwiftPrettyPrint,
//     nil
// ]

Pretty.printDebug(array)
// => [Optional(URL("https://github.com/YusukeHosonuma/SwiftPrettyPrint")), nil]

Pretty.prettyPrintDebug(array)
// =>
// [
//     Optional(URL("https://github.com/YusukeHosonuma/SwiftPrettyPrint")),
//     nil
// ]

Operator-based API

You can use operator based alias APIs that like Ruby.

This isn't needed to enclose in parentheses that convenient to long expression.

p >>> 42
// => 42

p >>> 42 + 2 * 4 // It can also be applied to expression
// => 50

p >>> String(string.reversed()).hasSuffix("eH")
// => true

pp >>> ["Hello", "World"]
// =>
// [
//     "Hello",
//     "World"
// ]
Operator syntax Equatable to
p >>> 42 Pretty.print(42)
pp >>> 42 Pretty.prettyPrint(42)
pd >>> 42 Pretty.printDebug(42)
ppd >>> 42 Pretty.prettyPrintDebug(42)

Format options

You can configure format options, shared or passed by arguments.

Indent size

You can specify indent size in pretty-print like following:

// Global option
Pretty.sharedOption = Pretty.Option(indentSize: 4)

let value = (bool: true, array: ["Hello", "World"])

// Use `sharedOption`
Pretty.prettyPrint(value)
// =>
// (
//     bool: true,
//     array: [
//         "Hello",
//         "World"
//     ]
// )

// Use option that is passed by argument
Pretty.prettyPrint(value, option: Pretty.Option(prefix: nil, indentSize: 2))
// =>
// (
//   bool: true,
//   array: [
//     "Hello",
//     "World"
//   ]
// )

colorized

Output strings can be ANSI colored.

The options for coloring are specified as follows:

Pretty.sharedOption = Pretty.Option(colored: true)

Under this configuration, the following outputs can be achieved in AppCode:

It works only on console that ANSI color supported (e.g. AppCode, Terminal.app). This does not includes Xcode debug console.

See also Terminal section.

Prefix and Label

You can specify a global prefix and a label (e.g. variable name) like following:

Pretty.sharedOption = Pretty.Option(prefix: "[DEBUG]")

let array = ["Hello", "World"]

Pretty.print(label: "array", array)
// => [DEBUG] array: ["Hello", "World"]

Pretty.p("array") >>> array
// => [DEBUG] array: ["Hello", "World"]

Outputting in Console.app

Applying .osLog to Option.outputStrategy makes the output be shown in Console.app:

Console.app Image

The outputs in xcode-debug-console will be the following.

Debug.sharedOption = Debug.Option(outputStrategy: .osLog)

let dog = Dog(id: DogId(rawValue: "pochi"), price: Price(rawValue: 10.0), name: "ใƒใƒ")

Debug.print(dog)
// => 2020-04-02 11:51:10.766231+0900 SwiftPrettyPrintExample[41397:2843004] Dog(id: "pochi", price: 10.0, name: "ใƒใƒ")

Integrations ๐Ÿ”Œ

LLDB

Please copy and add follows to your ~/.lldbinit (please create the file if the file doesn't exist):

command regex _p  's/(.+)/e -l swift -o -- var option = Pretty.sharedOption; option.prefix = nil; Pretty.print(%1, option: option)/'
command regex _pp 's/(.+)/e -l swift -o -- var option = Pretty.sharedOption; option.prefix = nil; Pretty.prettyPrint(%1, option: option)/'

or install via lowmad:

$ lowmad install https://github.com/YusukeHosonuma/SwiftPrettyPrint.git

Note: If you already installed 1.1.0 or older version of SwiftPrettyPrint via lowmad, please remove scripts manually before update. (e.g. rm /usr/local/lib/lowmad/commands/YusukeHosonuma-SwiftPrettyPrint/swift_pretty_print.py)

This lets you to use the lldb command in debug console as follows:

(lldb) e -l swift -- import SwiftPrettyPrint # If needed
(lldb) _p dog
Dog(id: "pochi", price: 10.0, name: "ใƒใƒ")

(lldb) _pp dog
Dog(
    id: "pochi",
    price: 10.0,
    name: "ใƒใƒ"
)

Terminal

SwiftPrettyPrint outputs log files to the following files automatically when running iOS Simulator or macOS.

  • /tmp/SwiftPrettyPrint/output.log
  • /tmp/SwiftPrettyPrint/output-colored.log (ANSI colored)

So you can read them from other tools such as tail or grep and others.

$ tail -F /tmp/SwiftPrettyPrint/output-colored.log

A output-colored.log is ANSI colorlized, so this looks beautiful on terminal.

Terminal

Customize

You can customize terminal ANSI colors by Debug.Option.theme property like as follows.

let theme = ColorTheme(
    type: { $0.green().bold() },
    nil: { $0.yellow() },
    bool: { $0.yellow() },
    string: { $0.blue() },
    number: { $0.cyan() },
    url: { $0.underline() }
)

Debug.sharedOption = Debug.Option(theme: theme)

ANSI colors can be easily specified using ColorizeSwift.

Did you create a beautiful theme?

Please add new theme to ColorTheme.swift and create PR.

public struct ColorTheme {
    ...    
+   public static let themeName = ColorTheme(
+       type: { ... },
+       nil: { ... },
+       bool: { ... },
+       string: { ... },
+       number: { ... },
+       url: { ... }
+   )
    
    public var type: (String) -> String
    public var `nil`: (String) -> String
    ...

Thanks!

SwiftUI

You can use prettyPrint() and prettyPrintDebug() on any View.

// Standard API.
Text("Swift")
    .prettyPrint()
    .prettyPrintDebug()

// You can specify label if needed.
Text("Swift")
    .prettyPrint(label: "๐ŸŽ")
    .prettyPrintDebug(label: "๐ŸŠ")

This extension is useful to examine the internal structure.

Combine

You can use prettyPrint() operator in Combine framework.

[[1, 2], [3, 4]]
    .publisher
    .prettyPrint("๐ŸŒ")
    .sink { _ in }
    .store(in: &cancellables)
// =>
// ๐ŸŒ: receive subscription: [[1, 2], [3, 4]]
// ๐ŸŒ: request unlimited
// ๐ŸŒ: receive value:
// [
//     1,
//     2
// ]
// ๐ŸŒ: receive value:
// [
//     3,
//     4
// ]
// ๐ŸŒ: receive finished

You can specify when: and format:.

[[1, 2], [3, 4]]
    .publisher
    .prettyPrint("๐ŸŒ", when: [.output, .completion], format: .singleline)
    .sink { _ in }
    .store(in: &cancellables)
// =>
// ๐ŸŒ: receive value: [1, 2]
// ๐ŸŒ: receive value: [3, 4]
// ๐ŸŒ: receive finished

You can use alias API p() and pp() too.

[[1, 2], [3, 4]]
    .publisher
    .p("๐ŸŽ")  // Output as single-line
    .pp("๐ŸŠ") // Output as multiline
    .sink { _ in }
    .store(in: &cancellables)

Installation

CocoaPods (Recommended)

pod "SwiftPrettyPrint", "~> 1.2.0", :configuration => "Debug" # enabled on `Debug` build only

The example app is here.

Carthage

github "YusukeHosonuma/SwiftPrettyPrint"

Swift Package Manager

Add the following line to the dependencies in your Package.swift file:

.package(url: "https://github.com/YusukeHosonuma/SwiftPrettyPrint.git", .upToNextMajor(from: "1.2.0"))

Finally, include "SwiftPrettyPrint" as a dependency for your any target:

let package = Package(
    // name, platforms, products, etc.
    dependencies: [
        .package(url: "https://github.com/YusukeHosonuma/SwiftPrettyPrint.git", .upToNextMajor(from: "1.2.0")),
        // other dependencies
    ],
    targets: [
        .target(name: "<your-target-name>", dependencies: ["SwiftPrettyPrint"]),
        // other targets
    ]
)

Alternatively, use Xcode integration. This function is available since Xcode 10.

Recommend Settings ๐Ÿ“

If you don't want to write an import statement when debugging.

We recommend to create Debug.swift and to declaration any type as typealias like following:

// Debug.swift
#if canImport(SwiftPrettyPrint)
    import SwiftPrettyPrint
    typealias Debug = SwiftPrettyPrint.Pretty // You can use short alias such as `D` too.
#endif

You don't need to write a import statement in each sources any longer.

// AnySource.swift
Debug.print(42)
Debug.prettyPrint(label: "array", array)

Note: This can't be used to the operator-based API such as p >>>. (This is a Swift language's limitation)

Requirements

  • Xcode 11.3+ (Swift 5.1+)
  • Platforms
    • iOS 10.0+
    • macOS 10.12+
    • watchOS 5.0+
    • tvOS 12.0+

Development

Require:

  • Xcode 11.3.1
    • Note: But run tests are failed on macOS 11.0.1, please use make test or latest version of Xcode to run unit tests.
  • pre-commit

Execute make setup to install development tools to system (not include Xcode 11.3).

$ make help
setup      Install requirement development tools to system and setup (not include Xcode 11.3)
build      swift - build
test       swift - test
xcode      swift - generate xcode project
format     format sources by SwiftFormat
lint       cocoapods - lint podspec
release    cocoapods - release
info       cocoapods - show trunk information

Author

Developed by Penginmura.

More Repositories

1

Effective-SwiftUI

๐Ÿ“˜ Effective SwiftUI
283
star
2

SwiftUI-Common

SwiftUI components that seem to be highly reusable.
Swift
82
star
3

SwiftUI-Simulator

๐Ÿ“ฑ Simulate device configurations in real-time. (and useful tools for development)
Swift
79
star
4

Swift-Evolution-Browser

Swift Evolution Browser
Swift
75
star
5

SwiftUI-LifeGame

The Conway's Game of Life that build with SwiftUI.
Swift
65
star
6

SwiftParamTest

Parameterized test for Swift
Swift
57
star
7

UserDefaultsBrowser

๐Ÿ” Browse and edit UserDefaults on your app
Swift
33
star
8

SFReadableSymbols

High readable code with SFSymbols.
Swift
14
star
9

iOS-MVP-Sample

Swift
11
star
10

DummyInn

ใƒ€ใƒŸใƒผ็”ปๅƒใ‚’็”Ÿๆˆใ™ใ‚‹ macOS ใƒกใƒ‹ใƒฅใƒผใƒใƒผใ‚ขใƒ—ใƒช
Swift
10
star
11

LifeGame

Swift Library for the Game of Life.
Swift
7
star
12

xcode-open

Open Xcode in terminal (with specify version)
Swift
6
star
13

E2DC

Extract English from Documentation Comment.
Swift
6
star
14

swift-commons

Simple helper swift extensions for easily development.
Swift
6
star
15

ObservableObjectDebugger

Watch for ObservableObject in real time.
Swift
5
star
16

SHList

HList for Swift by statically meta-programming.
Swift
5
star
17

assert-diff

Assert equals with readable diff report for Crystal.
Crystal
5
star
18

SwiftyFirestore

Firestore on the S(wift) strings.
Swift
4
star
19

swift-heredoc

Heredoc in Swift
Swift
3
star
20

Flatten

Flatten method reference that resolved to SE-0042.
Swift
3
star
21

nene

Remove ANSI escape codes in file.
Rust
2
star
22

SwiftRLE

Run-length encoding (RLE) library for Swift.
Swift
2
star
23

LifeWikiScraper

Scraper for LifeWiki.
Swift
2
star
24

workspace

Workspace since 201609.
HTML
2
star
25

Lang100-Haskell

http://www.cl.ecei.tohoku.ac.jp/nlp100/#
Haskell
1
star
26

homebrew-fix-module

Ruby
1
star
27

homebrew-swift-emmet

Ruby
1
star
28

dotfiles

dotfiles for macOS High Sierra
Shell
1
star
29

fix-module

Auto-fix module of .hs files from the definition of `package.yaml`.
Haskell
1
star
30

homebrew-spm-boot

Ruby
1
star
31

SwiftCheckMathMagic

TDD โœ• Property-based Testing (SwiftCheck) ใงๆ•ฐๅญฆใƒ‘ใ‚บใƒซใ‚’ๆคœ่จผใ—ใฆใฟใ‚‹
Swift
1
star
32

homebrew-xcode-open

Ruby
1
star
33

SwiftUI-Needle-Multimodule

SwiftUI x Needle(DI) x Multimodule(SPM) sample app.
Swift
1
star
34

YusukeHosonuma.github.io

1
star
35

coding-interview-189

ไธ–็•Œใง้—˜ใ†ใƒ—ใƒญใ‚ฐใƒฉใƒŸใƒณใ‚ฐๅŠ›ใ‚’้›ใˆใ‚‹ๆœฌ ~ใ‚ณใƒผใƒ‡ใ‚ฃใƒณใ‚ฐ้ขๆŽฅ189ๅ•ใจใใฎ่งฃๆณ• ใ‚’ Haskell ใง่งฃใ„ใฆใฟใ‚‹
Haskell
1
star
36

swift-emmet

Generate struct and class as simple syntax.
Haskell
1
star
37

homebrew-nene

Ruby
1
star