A Quick Swift Script Yak Shave

[Updated Version with downloadable OS X service]
In the process of writing a longer post yesterday, I wanted to add a markdown table, and was once again annoyed at the mild PITA that it is to use pipe characters and then the formatting characters a lá:

|    title    |   title2   |  
| :---------: | :--------: |  
|  entry one  |  entry two |  
| entry three | entry four |  

Being aware of Brett Terpstra’s excellent [Markdown Services][markdownServices] that have a table cleanup function, but actually writing the da** tables is kind of annoying, so I in classic [Yak-Shaving][yakShave] fashion, I decided to write a simple [Swift script][OSXScripts] that would turn the following into the format above. Then make that into an [OS X service][automatorServices].

title, title2
entry one, entry two
entry three, entry four

It really wasn’t that tricky, and probably would have been at least as easy using python or ruby, but ¯_(ツ)_/¯. (<– typed using textexpander).

It’s written in Swift 3. I should use stdin and stdout, but the syntax for NSFileHandler changed enough, and I know so little of it, that I decided to punt on that, as I didn’t need the Yak that well shaven. Fortunately the readline function in a while loop works just fine and simply print(output) also works. Likewise the code is naive, could be more functional, does not handle many (any) exceptional cases or check for consistency, but again, it does the job for a simple case. (You know, I’m embarrassed for anyone to actually look at my code)

Likewise, I would like to add a small tweak so that I can optionally write it this way to add the alignment more easily:

title, title2, title3
>, -, <
entry one, entry two, entry three
entry four, entry five, entry six

that would translate the second line to:

| ---: | :---: | :--- |

But Yak-Shaving is done for now.

Entire script is here:

#!/usr/bin/swift

//
//  main.swift
//  CSVToTables
//
//  Created by Christopher Brandow on 7/12/16.
//  Copyright © 2016 flouu. All rights reserved.
//


import Foundation

func titleAndEntryFrom(string: String) -> (String, [String])? {
    var lines = string.characters.split{$0 == "\n"}.map(String.init)

    guard lines.count > 1, let titleLine = lines.first else {
        return nil
    }

    lines.removeFirst()
    return (titleLine, lines)

}

func markdownTableFromTitleAndEntries(title: String, body: [String]) -> String? {

    let titleMarkdown = markdownFrom(line: title)
    let entries = title.characters.split{$0 == ","}.map(String.init)

    var separatorMarkdown = "\n|"
    for _ in 0..<entries.count {
        separatorMarkdown += " :---: |"
    }
    var bodyMarkdown = ""

    for line in body {
        bodyMarkdown += markdownFrom(line: line)
    }

    return titleMarkdown + separatorMarkdown + bodyMarkdown
}

func markdownFrom(line: String) -> String {
    var markdown = "\n| "
    let entries = line.characters.split{$0 == ","}.map(String.init)

    for entry in entries {
        markdown += entry
        markdown += " |"
    }
    return markdown
}

var string = ""

while let thing = readLine(strippingNewline: false) {
    string += thing
}

if let titleAndBody = titleAndEntryFrom(string: string) {
    if let output = markdownTableFromTitleAndEntries(title: titleAndBody.0, body: titleAndBody.1) {
        print(output)
    }
}

[markdownServices]: http://brettterpstra.com/projects/markdown-service-tools/

[OSXScripts]: http://krakendev.io/blog/scripting-in-swift

[automatorServices]: http://arstechnica.com/apple/2011/03/howto-build-mac-os-x-services-with-automator-and-shell-scripting/

[yakShave]: http://www.hanselman.com/blog/YakShavingDefinedIllGetThatDoneAsSoonAsIShaveThisYak.aspx

 
19
Kudos
 
19
Kudos

Now read this

Poor Misunderstood “Someday/Maybe” List

I’m gonna write this on the fly without fully referring to canonical “Getting Things Done” by David Allen, but I had a helpful realization when I pondered a problem that a friend (I’ll call him Sodmund) and I were having with regards to... Continue →