Adding syntax highlighting and source file support for TypeScript to Xcode

Thanks to a prior solution created by Steve Troughton-Smith for Lua, I was able to hack together an Xcode Plug-In (yeah, those still exist) for 10.1.

TypeScript repo is here at github.

To install, quit Xcode. Run setup.sh to add the xclangspec and ideplugin info to your ~/Library/Developer/Xcode folders. Then launch Xcode, agree to allow the plug-in to run, and then add your ts files.

The file inspector will still say they’re MPEG-2 Transport Stream files but you’ll be able to see the text, the text will be formatted, and you can use Xcode to search for content within the files. Let me know if it works for you.

The xcplugin and the xclangspec were easy to put together, because I just riffed on JavaScript’s syntax. Other languages will take a bit more work because you have to set up a list of keywords and their characters and syntax coloring rules, which may or may not lend themselves to easy lexer support.

Swift 5 Interpolation Part 3: Dates and Number Formatters

I’ve already posted about using string interpolation to customize Optional presentation and for coercing integer values via radix and to conditionalize text, and yet there is still so much more you can do with this new language feature.

Consider formatters. Both Swift and Cocoa/Cocoa touch support a number of these, ranging from numbers and currency to dates and times. They are a natural interpolation fit.

For example, dates are easy right out of the box. Just pass a formatter and you’re done. Note that I skip the formatter label. You’ll see why in just a second.

public extension String.StringInterpolation {
  mutating func appendInterpolation(_ value: Date, _ formatter: DateFormatter) {
    appendLiteral(formatter.string(from: value))
  }
}

For dates, it’s more about how do you create formatters than about interpolating them. Here’s the design I’m using right now:

public extension DateFormatter {
  /// Returns an initialized `DateFormatter` instance
  static func format(date: Style, time: Style) -> DateFormatter {
    let formatter = DateFormatter()
    formatter.locale = Locale.current
    (formatter.dateStyle, formatter.timeStyle) = (date, time)
    return formatter
  }
}

For example:

print("\(Date(), .format(date: .short, time: .none))") // 12/16/18

I left off the formatter: label because the call to format documents the role of the second argument.

I initially went with a convenience initializer, along the same lines, but the calls were uglier:

print("\(Date(), DateFormatter(date: .none, time: .long))") // 8:20:15 AM MST

I also tried static preset properties and option sets, as well as dateStyle:timeStyle: interpolation arguments as but none of them really felt as readable as the format(date:time:) approach.

Number formats are a bit harder as they only work with NSNumber, which means you either have to create interpolators for both BinaryInteger and FloatingPoint, or you have to use some magic. Brent Royal-Gordon tried helping me work with _ObjectiveCBridgeable but I couldn’t get it to work. For some reason, Swift just wouldn’t pick up, for example, Double.pi as a bridgeable value.

For right now, I have this, which I’m not particularly happy with:

public extension String.StringInterpolation {
  /// Interpolates a floating point value using a
  /// number formatter.
  mutating func appendInterpolation<Value: FloatingPoint>(_ number: Value, formatter: NumberFormatter) {
    if
      let value = number as? NSNumber,
      let string = formatter.string(from: value) {
      appendLiteral(string)
    } else {
      appendLiteral("Unformattable<\(number)>")
    }
  }
  
  /// Interpolates an integer value using a number formatter
  mutating func appendInterpolation<Value: BinaryInteger>(_ number: Value, formatter: NumberFormatter) {
    if
      let value = number as? NSNumber,
      let string = formatter.string(from: value) {
      appendLiteral(string)
    } else {
      appendLiteral("Unformattable<\(number)>")
    }
  }
}

Creating number and currency formatters with NumberFormatter() is an ugly and tedious task. For example, here’s a formatter that sets rounding, localization, padding, and digit count:

let formatter = NumberFormatter()
formatter.localizesFormat = true
formatter.roundingMode = .halfUp
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 4
formatter.paddingPosition = .beforePrefix
formatter.paddingCharacter = "0"
formatter.minimumIntegerDigits = 5

"\(Double.pi, formatter: formatter)" // 00003.1416
"\(5, formatter: formatter)" // 00005.0

There really should be better and Swiftier ways to express these formatting preferences. For one thing, the minimum and maximum stuff could be expressed as ranges specific to the whole and fractional parts. I’m not convinced there should be just one formatter type devoted to handling integers, floating point numbers, and currency. Why not three?

Integers, to my best understanding, don’t need to worry about localization. And why not throw radix control into the IntegerFormatter mix while you’re at it? I’d imagine a well-designed integer formatter would easily replace my radix/prefix/bytewise/width interpolation that I used in a recent post.

In fact, I think I’ll design exactly that. Off to Xcode…

Some fantastic coverage of interpolation from Olivier Halligon here: Part 1 and Part 2.

My prosaic kicking the wheels repo is over at GitHub.

(And I’m trying to redesign Olivier’s attributed strings because somehow I feel they should be enumeration cases with associated value payloads rather than static members.)

More fun with Swift 5 String Interpolation: Radix formatting

I’m still kicking the tires and enjoying the new string interpolation features in Swift 5. Today’s extension enables (optionally padded) radix-based interpolation. You interpolate a number and specify a radix, the numerical base used to present it.

For example:

"\(42, radix: .hex)" // 2a
"\(42, radix: .binary)" // 101010
"\(42, radix: .octal)" // 52
"\(0x2a, radix: .decimal)" // 42
"\(15, radix: .hex, prefix: true, toWidth: 2)" // 0x0F

With padding you can ensure, for example, that a non-wide color is presented using two digits per color, with or without a prefix. Start with 15 and end up with F, 0F, or 0x0F , as desired.

It’s a simple extension for a task I use pretty regularly. I decided to use lowercase prefixes (0x and 0b) and uppercase hex (7F vs 7f). If you’d rather swap that out, change the prefix property and/or the first line in the interpolation:

public extension String.StringInterpolation {
    /// Represents a single numeric radix
    enum Radix: Int {
        case binary = 2, octal = 8, decimal = 10, hex = 16
        
        /// Returns a radix's optional prefix
        var prefix: String {
             return [.binary: "0b", .octal: "0o", .hex: "0x"][self, default: ""]
        }
    }
    
    /// Return padded version of the value using a specified radix
    mutating func appendInterpolation<I: Binary Integer>(_ value: I, radix: Radix, prefix: Bool = false, toWidth width: Int = 0) {
        
        // Values are uppercased, producing `FF` instead of `ff`
        var string = String(value, radix: radix.rawValue).uppercased()
        
        // Strings are pre-padded with 0 to match target widths
        if string.count < width {
            string = String(repeating: "0", count: max(0, width - string.count)) + string
        }
        
        // Prefixes use lower case, sourced from `String.StringInterpolation.Radix`
        if prefix {
            string = radix.prefix + string
        }
        
        appendInterpolation(string)
    }
}

I haven’t had a chance to test this much so if you see any issues, please let me know.

I have more to follow with more general NumberFormatter approaches that extend the interpolator (thanks, Dave DeLong!) and some fun suggestions and examples that will cover the new custom string delimiters.

The Beauty of Swift 5 String Interpolation

Thanks to SE-0228, you can control exactly how you want string interpolations to print. Thank you Brent for giving this to us. It’s a doozy! Let me share some examples.

Consider printing optionals. You use:

"There's \(value1) and \(value2)"

And get an instant warning:

You can click the fixes to suppress the warning but you’ll still get an output that looks like this: “There’s Optional(23) and nil”.

"There's \(String(describing: value1)) and \(String(describing: value2))"

Now you can strip the “Optional” and produce “There’s 23 and nil”, allowing you to print values directly:

extension String.StringInterpolation {
    /// Provides `Optional` string interpolation without forcing the
    /// use of `String(describing:)`.
    public mutating func appendInterpolation(_ value: T?, default defaultValue: String) {
        if let value = value {
            appendInterpolation(value)
        } else {
            appendLiteral(defaultValue)
        }
    }
}

// There's 23 and nil
"There's \(value1, default: "nil") and \(value2, default: "nil")"

You might create a set of styles and custom interpolation to support consistent presentation for optional output:

extension String.StringInterpolation {
    /// Optional Interpolation Styles
    public enum OptionalStyle {
        /// Includes the word `Optional` for both `some` and `none` cases
        case descriptive
        /// Strips the word `Optional` for both `some` and `none` cases
        case stripped
        /// Uses system interpolation, which includes the word `Optional` for
        /// `some` cases but not `none`.
        case `default`
    }
    
    /// Interpolates optional values using a supplied `optStyle` style
    public mutating func appendInterpolation(_ value: T?, optStyle style: String.StringInterpolation.OptionalStyle) {
        switch style {
        // Includes the word `Optional` for both `some` and `none` cases
        case .descriptive:
            if value == nil {
                appendLiteral("Optional(nil)")
            } else {
                appendLiteral(String(describing: value))
            }
        // Strips the word `Optional` for both `some` and `none` cases
        case .stripped:
            if let value = value {
                appendInterpolation(value)
            } else {
                appendLiteral("nil")
            }
        // Uses system interpolation, which includes the word `Optional` for
        // `some` cases but not `none`.
        default:
            appendLiteral(String(describing: value))
        }
    }
    
    /// Interpolates an optional using "stripped" interpolation, omitting
    /// the word "Optional" from both `.some` and `.none` cases
    public mutating func appendInterpolation(describing value: T?) {
        appendInterpolation(value, optStyle: .stripped)
    }

}

// "There's Optional(23) and nil"
"There's \(value1, optStyle: .default) and \(value2, optStyle: .default)"

// "There's Optional(23) and Optional(nil)"
"There's \(value1, optStyle: .descriptive) and \(value2, optStyle: .descriptive)"

// "There's 23 and nil"
"There's \(describing: value1) and \(describing: value2)"

Interpolation isn’t limited to tweaking optionals. Say you want to control whether a string is added without having to use a ternary expression with an empty string:

// Include on success (Thanks, Nate Cook)
extension String.StringInterpolation {
    /// Provides Boolean-guided interpolation that succeeds only when the condition
    /// evaluates to true.
    mutating func appendInterpolation(if condition: @autoclosure () -> Bool, _ literal: StringLiteralType) {
        guard condition() else { return }
        appendLiteral(literal)
    }
}

// Old
"Cheese Sandwich \(isStarred ? "(*)" : "")"

// New
"Cheese Sandwich \(if: isStarred, "(*)")"

There’s lots more you can do and it’s all exciting and fun.

Xcode Symbology Challenge! Find examples, identify icons, gain fame and glory

You know those little icons in the Xcode developer docs? Like the 4 squares for frameworks or the M for method? How many can you find and give examples for? Also how many can you identify off the top of your head? Do you know what each of these are and what they represent?

What follows is an exhaustive list sourced from an internal Xcode framework. For each of the following, your challenge is to describe what the icon looks like and offer an example that uses the icon. For example “T” is a type alias. You can find one by following UIKit > Drawing > UIGraphicsPDFRenderer.DrawingActions or searching for DrawingActions.

  • article
  • category
  • class
  • class extension
  • constant
  • endpoint
  • enum
  • extension
  • field
  • framework
  • function
  • group
  • local_variable
  • macro
  • method
  • object
  • operator
  • property
  • protocol
  • sample code
  • struct
  • subscript
  • typedef
  • union
  • variable

Have fun and drop a comment with a link to your finds. Please don’t put answers here directly as that may spoil the challenge for others.

Prototyping CoreGraphics in the Playground

No matter how flaky, I love using playgrounds to prototype Core Graphics, SpriteKit, and many other see-as-you-go technologies. They’re fantastic for building out specific custom content with a bare minimum of coding investment. You get a lot of win for very little time.

I was helping someone out the other day, explaining the strokeEnd keypath (versus the path keypath) and building a playground showed it off to perfection.

Admittedly, it helps to have quick helper code on-hand for quick starts. I have playground-specific setup code, handing me a view controller (called vc) and a centered view, ready to start demo-ing in this one.

I also have a couple of pages of code (like the layer(path:) constructor, the animateStrokemethods, and the schedule() utility off page, in the support module. They’re all highly reusable. It’s a pity in-playground debugging is so dreadful. It would be an ideal module-building tool if not for that: build and explore (and ideally build tests) in a single place, without having to be in a fixed workspace lacking the exploration feature. Adding “convert this exploration into a test” would be icing on top.

I’m disappointed that playground-specific visualizations built for teaching and demos don’t transfer to the debugger for real-world production support. I don’t see any reason why a CGPoint instance should get a pretty graphic representation but a CGAffineTransform, for which I have quite a full presentation, does not.

I can use custom mirroring to produce valuable output for dump, and therefore for printing objects in the debugger but not for debug quicklooks. Plus as far as I can tell the custom NSObject-only quicklooks haven’t been updated in years and there’s no hint of extending this to structs and enums.

By the way, what’s the deal with all the API audits? How long are these going to go on? If you thought updating the app delegate was a minor nuisance, you haven’t seen what’s happened to all the constants and Core Graphics APIs. This update is huge and disruptive…

Return to Sender: My first dive into watchOS

Just wrote my first two watchOS apps. The first, intended to provide voice coaching for physical therapy exercises, was a failure. Timing just wasn’t reliable and the errors built up more and more over a session of repeated counts, holds, and “almost there”/”two more”/”last one” prompts.

The second was a simple D&D dice set and much more successful. (Barring, of course, my miserable sense of interface design.)

It consists of an iOS app paired with a watchOS extension, which runs as its own watchOS app, allowing anyone with an arm and a need for d20 to roll at will.

The WatchOS APIs were disappointing at first glance. For one thing watch buttons use target-action but provide no sense of sender. A single iOS call must be split into 7 calls on the watch:

// iOS. I used tags. Sue me.
@IBAction func roll(_ button: UIButton) {
    let value = Int.random(in: 1 ... button.tag)
    let percent = button.tag == 100 ? "%" : ""
    label.text = "\(value)\(percent)"
}

// watchOS
@IBAction func d4()  { label.setText("\(Int.random(in: 1...4))")  }
@IBAction func d6()  { label.setText("\(Int.random(in: 1...6))")  }
@IBAction func d8()  { label.setText("\(Int.random(in: 1...8))")  }
@IBAction func d10() { label.setText("\(Int.random(in: 1...10))") }
@IBAction func d12() { label.setText("\(Int.random(in: 1...12))") }
@IBAction func d20() { label.setText("\(Int.random(in: 1...20))") }
@IBAction func dPercent() { label.setText("\(Int.random(in: 1...100))%") }

There’s no auto-layout so far as I can tell, so you either “fill” things or you give them fixed sizes. I couldn’t figure out a way to split my buttons into thirds of the available screen space.

Setting a label’s text is a matter of a function call not a property assignment. That was surprising to me. I’m not sure what advantage was gained here beyond violating the principle of least astonishment.

I had to design my app’s interface in the WatchKitApp target but implement it in the extension target. This may be perfectly normal and in-line with other extensions on iOS but I haven’t spent much time there so it raised my eyebrows a bit. You add your app assets in the app, your complications (which I did not build) in the extension.

Right now on my priority list, I’d like to build something similar to the “breathe” app. I don’t entirely know where to start. I need to use a notification system to launch the app at set intervals, n times a day, preferably during the work day, and then use some kind of coached interaction with haptic feedback. My immediate goal is one that has me regularly exercise my sitting back muscles to build up strength.

I’m a bit sad about the timing issues I encountered with my first jab at the coaching app. I may approach that again with a new design as having my wrist count and prompt would be a lot better than having to do all the work myself (I always lose my place) or having to keep my phone nearby.

My need for reps, holds, and rest periods are simple. And while I don’t particularly like the scrolling wheel that seems to take the place of segmented controls, I can live with them.

If you’d like to see my first project (either to be inspired or to offer critiques), I’ve left a copy at github.

Unwinding a modal segue on a single view controller

For whatever reason, my unwind segues for modal presentations weren’t working when my presenting source was my navigation’s root controller. This appears to be a common issue if you hunt around for “modal unwind doesn’t work”. A lot of the advice simply went: “You just can’t do that.”

After spending far too much time dealing with, I discovered that the autocomplete version, namely:

@IBAction func unwind(for unwindSegue: UIStoryboardSegue, towards subsequentVC: UIViewController)

doesn’t work. Instead, what you need is:

@IBAction func unwindFor(_ unwindSegue: UIStoryboardSegue, towards subsequentVC: UIViewController)

If you notice, the difference is unwind(for vs unwindFor(. I figured this out by implementing

func canPerformUnwindSegueAction(_ action: Selector, from fromViewController: UIViewController, withSender sender: Any) -> Bool

and looking at the selector it expected to perform (specifically unwindFor:towards:). Moving the For outside fixed the problem and granted me a working unwind, allowing me to fetch state data from the modal controller and pass it back to the source.

I assume this issue arose because of the automatic translation of Cocoa APIs into Swift and I wonder if there are other issues that might arise from the same. Have you encountered such things? What are your thoughts?

 

Tuple Initialization

I’ve been wanting  tuple-initializable in Swift for Core Graphics, where it’s a drag to always use long and cumbersome initializers when I’m not building production code:

let point: CGPoint = (100, 50)

Yeah, it is better form to use labeled initializers but I’m anyone using CGPoint understands the correspondence between (x, y) coordinates. And I don’t want to just build CGPoint.init(_ x:, _ y:) extensions. I like the tuple form.

Right now, the closest you can get is the silly:

let point = (CGPoint.init as (CGFloat, CGFloat) -> CGPoint)(100, 50)

And that’s (pardon the pun) pointless.

It would be pretty cool to allow memberwise tuples with or without labels in place of  initializers when the tuple field types could be unambiguously determined:

let point: CGPoint = (x: 100, y: 50) 
// instead of: let point = CGPoint(x: 100, y: 50)
let person: Person = ("Mary", nil, "Santos")
// instead of: let person = Person(first: "Mary", middle: nil, last: "Santos")

It may be ugly but it would be hella useful in Playgrounds.

That darn Maps app

Dear Maps team,

Please don’t route me onto a dirt road again. It was super un-fun. I ended up going back up to I-80 and heading over to Wyoming from Nebraska, adding another state and about 5 hours to my trip including the not-joy of I-25 rush hour traffic instead of the much quieter I-76 through Fort Morgan.

It was impossible to get any live data from said dirt road so I just went with my gut until I could get directions again, which took about 2 hours, placing me just outside Cheyenne.

Navigation through Nebraska is always horrible horrible horrible, usually just blank tiles until I hit either Colorado or South Dakota. When going state to state, I’d like to cache tiles along several possible routes because with so much highway construction, I don’t want to be caught with blank tiles in the middle of Nebraska when I have to go twenty or forty miles off to the left or right to avoid a road that isn’t roading at the moment.

Caching tiles and directions along many possible routes would have helped the whole dirt road fiasco. The no-data-no-tiles-no-rerouting trap is both unsafe and unpleasant. Plus it made me miss Sidney, NE, with the only truck stop I’ve ever encountered in the United States that offered bidets (!) in their bathrooms. A true tourist’s experience.

While I’m venting, please respect my wishes about “No tolls” or “No highways” for my entire trip, even if I take a slight detour to avoid traffic. Forgetting “Show me how to get to [Someplace] avoiding tolls” when I reroute cost me  unnecessary funds recently by putting me onto 470, aka the hell road. I was properly billed (thankfully!) and paid immediately but no one voluntarily drives on E470.

Maps folk, please let me say “Show me how to get to Colombia, MO avoiding tolls and dirt roads” and remember that request until I’m safely at my destination. And let me add those requests as I’m driving. During rush hour, let me say “Hey, let’s get off the highways until I’m close to 225”. That’s totally doable from a programming point of view.

Speaking of slight detours, I generally know better than Maps how to tweak directions within the first few miles of my home. For example, I prefer to take the relatively quiet 13th and 14th streets from downtown instead of Colfax or 6th. There’s an incredibly unsafe left turn near our house that Maps always recommends. I drive a little further and make a safe U-turn at a light with a dedicated left turn signal.

I do these tweaks near my home all the time and Maps shouldn’t be fighting me on this, announcing updated directions every single block. I’d like a setting that limits any directions at all (after the initial announcement) for the first, say, mile or two or three away from my home or other “known” starting points that I could add to a list.

In fact, I know how to get to many major milestones within the greater Denver metropolitan area like 225 and Vasquez, and Hampden and 25, and Colorado and 70. I’d like to be able to have navigation kick off once  I’m near a known point or I’m close to the highway or fairly far along towards my destination. That shouldn’t be too hard to develop and customize, requiring no in-car interaction so it’s safe.

In many cases, I only need last mile assistance when driving in-city, including other cities I’m familiar with like Colorado Springs and Fort Collins. I wish I could ask for a “guide me when I’m close to” setting for these kinds of navigation requests.

Thank you all. You know I appreciate everything you do!