diff --git a/.travis.yml b/.travis.yml index ed1fe7c..cb645ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,12 @@ language: objective-c osx_image: xcode8 + +env: + - PLATFORM=iOS CODECOV=ios DESTINATION='platform=iOS Simulator,name=iPhone 6S' + - PLATFORM=Mac CODECOV=osx DESTINATION='platform=OS X' + - PLATFORM=tvOS CODECOV=tvos DESTINATION='platform=tvOS Simulator,name=Apple TV 1080p' + script: - xcodebuild -version - - xcodebuild -project SwiftyAttributes.xcodeproj -scheme SwiftyAttributesTests -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 6" -configuration Debug ONLY_ACTIVE_ARCH=YES -enableCodeCoverage YES test - - bash <(curl -s https://codecov.io/bash) -cF ios \ No newline at end of file + - xcodebuild -project SwiftyAttributes.xcodeproj -scheme "SwiftyAttributes" -destination "$DESTINATION" -configuration Debug -enableCodeCoverage YES CODE_SIGNING_REQUIRED=NO test + - bash <(curl -s https://codecov.io/bash) -cF "$CODECOV" diff --git a/ExampleApp-iOS/ViewController.swift b/ExampleApp-iOS/ViewController.swift index 1e31025..c8757bc 100644 --- a/ExampleApp-iOS/ViewController.swift +++ b/ExampleApp-iOS/ViewController.swift @@ -15,9 +15,9 @@ class ViewController: UITableViewController { private let attributedStrings: [NSAttributedString] = [ { - let attachment = NSTextAttachment() + let attachment = TextAttachment() attachment.image = UIImage(named: "Star") - let str = NSMutableAttributedString(string: "Attachment With Image") + let str = "Attachment With Image".attributedString str.replaceCharacters(in: 10 ..< 12, with: NSAttributedString(attachment: attachment)) return str }(), @@ -31,7 +31,7 @@ class ViewController: UITableViewController { "Link".withLink(URL(string: "https://google.com")!), "Obliqueness".withObliqueness(2), "Shadow".withShadow({ - let shadow = NSShadow() + let shadow = Shadow() shadow.shadowBlurRadius = 2 shadow.shadowOffset = CGSize(width: 3, height: -4) return shadow diff --git a/ExampleApp-macOS/AppDelegate.swift b/ExampleApp-macOS/AppDelegate.swift new file mode 100644 index 0000000..35a4a09 --- /dev/null +++ b/ExampleApp-macOS/AppDelegate.swift @@ -0,0 +1,12 @@ +// +// AppDelegate.swift +// ExampleApp-macOS +// +// Created by Eddie Kaiger on 11/26/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +import Cocoa + +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { } diff --git a/ExampleApp-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/ExampleApp-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2db2b1c --- /dev/null +++ b/ExampleApp-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ExampleApp-macOS/Assets.xcassets/Contents.json b/ExampleApp-macOS/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/ExampleApp-macOS/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ExampleApp-macOS/Base.lproj/Main.storyboard b/ExampleApp-macOS/Base.lproj/Main.storyboard new file mode 100644 index 0000000..6cab678 --- /dev/null +++ b/ExampleApp-macOS/Base.lproj/Main.storyboard @@ -0,0 +1,750 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ExampleApp-macOS/Info.plist b/ExampleApp-macOS/Info.plist new file mode 100644 index 0000000..9d1a361 --- /dev/null +++ b/ExampleApp-macOS/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2016 Eddie Kaiger. All rights reserved. + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + + diff --git a/ExampleApp-macOS/ViewController.swift b/ExampleApp-macOS/ViewController.swift new file mode 100644 index 0000000..2e01c92 --- /dev/null +++ b/ExampleApp-macOS/ViewController.swift @@ -0,0 +1,72 @@ +// +// ViewController.swift +// ExampleApp-macOS +// +// Created by Eddie Kaiger on 11/26/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +import Cocoa +import SwiftyAttributes + +class ViewController: NSViewController { + + fileprivate let attributedStrings: [NSAttributedString] = [ + { + let attachment = TextAttachment() + attachment.image = NSImage(named: "Star")! + let str = "Attachment With Image".attributedString + str.replaceCharacters(in: 10 ..< 12, with: NSAttributedString(attachment: attachment)) + return str + }(), + "Baseline Offset".withBaselineOffset(8.5), + "Background Color".withBackgroundColor(.blue), + "Expansion".withExpansion(0.8), + "Font".withFont(.boldSystemFont(ofSize: 20)), + "Kern".withKern(5.1), + "Default Ligatures".withLigatures(.default), + "No Ligatures".withLigatures(.none), + "Link".withLink(URL(string: "https://google.com")!), + "Obliqueness".withObliqueness(2), + "Shadow".withShadow({ + let shadow = Shadow() + shadow.shadowBlurRadius = 2 + shadow.shadowOffset = CGSize(width: 3, height: -4) + return shadow + }()), + "Stroke Color".withStrokeColor(.orange).withStrokeWidth(1), + "Stroke Width".withStrokeWidth(2.7), + "Strikethrough Style & Color".withStrikethroughColor(.green).withStrikethroughStyle(.styleDouble), + "Text Color".withTextColor(.brown), + "Text Effect".withTextEffect(.letterPressStyle), + "Underline Style & Color".withUnderlineColor(.red).withUnderlineStyle(.styleDouble), + "Writing Directions".withWritingDirections([.rightToLeftOverride]), + "Multiple Attributes".withAttributes([.baselineOffset(5), .font(.boldSystemFont(ofSize: 20)), .kern(4), .underlineStyle(.styleSingle), .underlineColor(.magenta), .strokeColor(.orange), .strokeWidth(3), .strikethroughColor(.green), .strikethroughStyle(.styleSingle), .backgroundColor(.yellow)]), + { + let str = "Partial Range Attributes".withUnderlineStyle(.styleSingle) + str.addAttributes([.underlineStyle(.styleDouble), .textColor(.blue)], range: 3 ..< 8) + str.addAttributes([.strikethroughStyle(.styleThick), .strikethroughColor(.purple)], range: 16 ..< 22) + str.setAttributes([.textColor(.red)], range: 22 ..< 24) + return str + }() + ] + + override func viewDidLoad() { + super.viewDidLoad() + + + } + +} + +extension ViewController: NSTableViewDataSource { + + func numberOfRows(in tableView: NSTableView) -> Int { + return attributedStrings.count + } + + func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { + return attributedStrings[row] + } + +} diff --git a/README.md b/README.md index 103658e..3dea341 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ Initializing attributed strings in `SwiftyAttributes` can be done several ways: - Using the `Attribute` enum extensions: ````swift - "Hello World".withAttributes([.underlineColor(.red), underlineStyle(.styleDouble)]) + "Hello World".withAttributes([.underlineColor(.red), .underlineStyle(.styleDouble)]) ```` - Using the `Attribute` enum in an initializer: @@ -127,24 +127,24 @@ extension NSAttributedString { func withAttribute(_ attribute: Attribute) -> NSMutableAttributedString func attributedSubstring(from range: Range) -> NSAttributedString func attribute(_ attrName: Attribute.Name, at location: Int, effectiveRange range: NSRangePointer? = nil) -> Attribute? + func attributes(in range: Range, options: NSAttributedString.EnumerationOptions = []) -> [([Attribute], Range)] + func enumerateAttributes(in enumerationRange: Range, options: NSAttributedString.EnumerationOptions = [], using block: (_ attrs: [Attribute], _ range: Range, _ stop: UnsafeMutablePointer) -> Void) + func enumerateAttribute(_ attrName: Attribute.Name, in enumerationRange: Range, options: NSAttributedString.EnumerationOptions = [], using block: (_ value: Any?, _ range: Range, _ stop: UnsafeMutablePointer) -> Void) } extension String { + var attributedString: NSMutableAttributedString func withAttributes(_ attributes: [Attribute]) -> NSMutableAttributedString func withAttribute(_ attribute: Attribute) -> NSMutableAttributedString } -```` - -# Goals +// ... and more! -The goal of version 3.1.0 will be full support for macOS, tvOS, and watchOS as well as additional helper methods to retrieve and enumerate attributes in an attributed string. - -If you have suggestions and feature requests, please feel free to open up an issue. +```` # Support -For questions and support, please open up an issue. +For questions, support, and suggestions, please open up an issue. # License diff --git a/SwiftyAttributes.podspec b/SwiftyAttributes.podspec index 48b46d4..f4de899 100644 --- a/SwiftyAttributes.podspec +++ b/SwiftyAttributes.podspec @@ -2,20 +2,26 @@ Pod::Spec.new do |s| s.name = "SwiftyAttributes" - s.version = "3.0.0" - s.summary = "Swift extensions that make it a breeze to work with attributed strings." + s.version = "3.1.0" + s.summary = "A Swifty API for attributed strings." s.description = <<-DESC - SwiftyAttributes provides extensions for the String and NSAttributedString classes that make it easier to create and modify attributed strings. + SwiftyAttributes provides a clean, Swifty API for dealing with NSAttributedStrings. DESC s.homepage = "https://github.com/eddiekaiger/SwiftyAttributes" s.license = { :type => "MIT", :file => "LICENSE" } s.author = { "Eddie Kaiger" => "eddiekaiger@gmail.com" } - s.source = { :git => "https://github.com/eddiekaiger/SwiftyAttributes.git", :tag => "v3.0.0" } - s.source_files = "SwiftyAttributes/*.swift" - s.platform = :ios, '8.0' + s.source = { :git => "https://github.com/eddiekaiger/SwiftyAttributes.git", :tag => "v3.1.0" } + + s.source_files = "SwiftyAttributes/Sources/common/*.swift" + s.osx.source_files = "SwiftyAttributes/Sources/macOS/*.swift" + + s.ios.deployment_target = '8.0' + s.osx.deployment_target = '10.11' + s.tvos.deployment_target = '9.0' + s.watchos.deployment_target = '2.0' end diff --git a/SwiftyAttributes.xcodeproj/project.pbxproj b/SwiftyAttributes.xcodeproj/project.pbxproj index b503d18..9112454 100644 --- a/SwiftyAttributes.xcodeproj/project.pbxproj +++ b/SwiftyAttributes.xcodeproj/project.pbxproj @@ -7,50 +7,72 @@ objects = { /* Begin PBXBuildFile section */ - C00CF8F31DA6142500B6C1BB /* WritingDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C00CF8F21DA6142500B6C1BB /* WritingDirection.swift */; }; - C0127C3C1DB2D5490047DF5A /* Attribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0127C3B1DB2D5490047DF5A /* Attribute.swift */; }; - C01C438D1DC472F000C49E5E /* TextEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = C01C438C1DC472F000C49E5E /* TextEffect.swift */; }; - C0335B5C1DC083A5009F9B51 /* NSAttributedString+SwiftyAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0335B5B1DC083A5009F9B51 /* NSAttributedString+SwiftyAttributes.swift */; }; - C0335B5E1DC083AE009F9B51 /* String+SwiftyAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0335B5D1DC083AE009F9B51 /* String+SwiftyAttributes.swift */; }; - C0335B601DC08409009F9B51 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0335B5F1DC08409009F9B51 /* Operators.swift */; }; - C0335B621DC086B3009F9B51 /* NSMutableAttributedString+SwiftyAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0335B611DC086B3009F9B51 /* NSMutableAttributedString+SwiftyAttributes.swift */; }; - C0335B641DC0877C009F9B51 /* WritingDirection_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0335B631DC0877C009F9B51 /* WritingDirection_Tests.swift */; }; - C0335B661DC087A3009F9B51 /* Operators_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0335B651DC087A3009F9B51 /* Operators_Tests.swift */; }; - C03658F21DC84CCA0051F06D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C03658EF1DC84B3F0051F06D /* Images.xcassets */; }; + C027C0C91DEA0A0100953C09 /* SpellingState_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C027C0C81DEA0A0100953C09 /* SpellingState_Tests.swift */; }; + C027C0CB1DEA452500953C09 /* Attribute+Sequence_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C027C0CA1DEA452500953C09 /* Attribute+Sequence_Tests.swift */; }; C03658FA1DC859D80051F06D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C03658F91DC859D80051F06D /* AppDelegate.swift */; }; C03658FC1DC859D80051F06D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C03658FB1DC859D80051F06D /* ViewController.swift */; }; C03658FF1DC859D80051F06D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C03658FD1DC859D80051F06D /* Main.storyboard */; }; C03659011DC859D80051F06D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C03659001DC859D80051F06D /* Assets.xcassets */; }; C03659041DC859D80051F06D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C03659021DC859D80051F06D /* LaunchScreen.storyboard */; }; C03659091DC85AE40051F06D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C03658EF1DC84B3F0051F06D /* Images.xcassets */; }; - C05C54F71DA61F4E007514C1 /* Ligatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05C54F61DA61F4E007514C1 /* Ligatures.swift */; }; - C08D04131DC39B5500575F98 /* NSMutableAttributedString_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08D04121DC39B5500575F98 /* NSMutableAttributedString_Tests.swift */; }; - C08D04151DC3B16A00575F98 /* NSAttributedString_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08D04141DC3B16A00575F98 /* NSAttributedString_Tests.swift */; }; - C0D753FB1DC5C77E00BB9754 /* TextEffect_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D753FA1DC5C77E00BB9754 /* TextEffect_Tests.swift */; }; - C0D753FD1DC5C88900BB9754 /* Attribute_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D753FC1DC5C88900BB9754 /* Attribute_Tests.swift */; }; - C0E211541D9EC5C000623F02 /* SwiftyAttributes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0E2114A1D9EC5C000623F02 /* SwiftyAttributes.framework */; }; - C0E211591D9EC5C000623F02 /* SwiftyAttributes_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0E211581D9EC5C000623F02 /* SwiftyAttributes_Tests.swift */; }; - C0E2115B1D9EC5C000623F02 /* SwiftyAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = C0E2114D1D9EC5C000623F02 /* SwiftyAttributes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C05082291DFA72F700D39B3B /* Attribute+Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C050821E1DFA72F700D39B3B /* Attribute+Sequence.swift */; }; + C050822A1DFA72F700D39B3B /* Attribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = C050821F1DFA72F700D39B3B /* Attribute.swift */; }; + C050822B1DFA72F700D39B3B /* AttributeName.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05082201DFA72F700D39B3B /* AttributeName.swift */; }; + C050822C1DFA72F700D39B3B /* Ligatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05082211DFA72F700D39B3B /* Ligatures.swift */; }; + C050822D1DFA72F700D39B3B /* NSAttributedString+SwiftyAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05082221DFA72F700D39B3B /* NSAttributedString+SwiftyAttributes.swift */; }; + C050822E1DFA72F700D39B3B /* NSMutableAttributedString+SwiftyAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05082231DFA72F700D39B3B /* NSMutableAttributedString+SwiftyAttributes.swift */; }; + C050822F1DFA72F700D39B3B /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05082241DFA72F700D39B3B /* Operators.swift */; }; + C05082301DFA72F700D39B3B /* String+SwiftyAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05082251DFA72F700D39B3B /* String+SwiftyAttributes.swift */; }; + C05082311DFA72F700D39B3B /* TextEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05082261DFA72F700D39B3B /* TextEffect.swift */; }; + C05082321DFA72F700D39B3B /* VerticalGlyphForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05082271DFA72F700D39B3B /* VerticalGlyphForm.swift */; }; + C05082331DFA72F700D39B3B /* WritingDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05082281DFA72F700D39B3B /* WritingDirection.swift */; }; + C0782E391DEAB30800E1B99F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0782E381DEAB30800E1B99F /* AppDelegate.swift */; }; + C0782E3B1DEAB30800E1B99F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0782E3A1DEAB30800E1B99F /* ViewController.swift */; }; + C0782E3D1DEAB30800E1B99F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C0782E3C1DEAB30800E1B99F /* Assets.xcassets */; }; + C0782E401DEAB30800E1B99F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C0782E3E1DEAB30800E1B99F /* Main.storyboard */; }; + C09633E01DD806F600059332 /* SwiftyAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = C09633DC1DD8056000059332 /* SwiftyAttributes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C0DB42EC1DDED3500093A6FA /* NSAttributedString+macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0DB42EB1DDED3500093A6FA /* NSAttributedString+macOS.swift */; }; + C0E1C9541DD319D50068E85C /* SwiftyAttributes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0E1C94B1DD319D50068E85C /* SwiftyAttributes.framework */; }; + C0E1C96A1DD31A0D0068E85C /* Attribute_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D753FC1DC5C88900BB9754 /* Attribute_Tests.swift */; }; + C0E1C96B1DD31A0D0068E85C /* NSMutableAttributedString_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08D04121DC39B5500575F98 /* NSMutableAttributedString_Tests.swift */; }; + C0E1C96C1DD31A0D0068E85C /* NSAttributedString_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08D04141DC3B16A00575F98 /* NSAttributedString_Tests.swift */; }; + C0E1C96D1DD31A0D0068E85C /* SwiftyAttributes_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0E211581D9EC5C000623F02 /* SwiftyAttributes_Tests.swift */; }; + C0E1C96E1DD31A0D0068E85C /* WritingDirection_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0335B631DC0877C009F9B51 /* WritingDirection_Tests.swift */; }; + C0E1C96F1DD31A0D0068E85C /* Operators_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0335B651DC087A3009F9B51 /* Operators_Tests.swift */; }; + C0E1C9701DD31A0D0068E85C /* TextEffect_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D753FA1DC5C77E00BB9754 /* TextEffect_Tests.swift */; }; + C0E1C99C1DD31C640068E85C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C03658EF1DC84B3F0051F06D /* Images.xcassets */; }; + C0F001761DDD8EA5009AD8E0 /* SpellingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F001751DDD8EA5009AD8E0 /* SpellingState.swift */; }; + C0F96A031DEDE1D300D039A4 /* VerticalGlyphForm_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F96A021DEDE1D300D039A4 /* VerticalGlyphForm_Tests.swift */; }; + C0F96A051DEDE23200D039A4 /* String+macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0F96A041DEDE23200D039A4 /* String+macOS.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - C0E211551D9EC5C000623F02 /* PBXContainerItemProxy */ = { + C0782E461DEABEED00E1B99F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = C0E211411D9EC5C000623F02 /* Project object */; proxyType = 1; - remoteGlobalIDString = C0E211491D9EC5C000623F02; + remoteGlobalIDString = C0E1C94A1DD319D50068E85C; remoteInfo = SwiftyAttributes; }; + C0782E481DEABEF100E1B99F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C0E211411D9EC5C000623F02 /* Project object */; + proxyType = 1; + remoteGlobalIDString = C0E1C94A1DD319D50068E85C; + remoteInfo = SwiftyAttributes; + }; + C0E1C9551DD319D50068E85C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C0E211411D9EC5C000623F02 /* Project object */; + proxyType = 1; + remoteGlobalIDString = C0E1C94A1DD319D50068E85C; + remoteInfo = "SwiftyAttributes-macOS"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - C00CF8F21DA6142500B6C1BB /* WritingDirection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WritingDirection.swift; sourceTree = ""; }; - C0127C3B1DB2D5490047DF5A /* Attribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Attribute.swift; sourceTree = ""; }; - C01C438C1DC472F000C49E5E /* TextEffect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEffect.swift; sourceTree = ""; }; - C0335B5B1DC083A5009F9B51 /* NSAttributedString+SwiftyAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+SwiftyAttributes.swift"; sourceTree = ""; }; - C0335B5D1DC083AE009F9B51 /* String+SwiftyAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+SwiftyAttributes.swift"; sourceTree = ""; }; - C0335B5F1DC08409009F9B51 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; - C0335B611DC086B3009F9B51 /* NSMutableAttributedString+SwiftyAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+SwiftyAttributes.swift"; sourceTree = ""; }; + C027C0C81DEA0A0100953C09 /* SpellingState_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpellingState_Tests.swift; sourceTree = ""; }; + C027C0CA1DEA452500953C09 /* Attribute+Sequence_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Attribute+Sequence_Tests.swift"; sourceTree = ""; }; C0335B631DC0877C009F9B51 /* WritingDirection_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WritingDirection_Tests.swift; sourceTree = ""; }; C0335B651DC087A3009F9B51 /* Operators_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators_Tests.swift; sourceTree = ""; }; C03658EF1DC84B3F0051F06D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = SwiftyAttributesTests/Images.xcassets; sourceTree = SOURCE_ROOT; }; @@ -61,17 +83,37 @@ C03659001DC859D80051F06D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; C03659031DC859D80051F06D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; C03659051DC859D80051F06D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C05C54F61DA61F4E007514C1 /* Ligatures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Ligatures.swift; sourceTree = ""; }; + C050821E1DFA72F700D39B3B /* Attribute+Sequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Attribute+Sequence.swift"; path = "common/Attribute+Sequence.swift"; sourceTree = ""; }; + C050821F1DFA72F700D39B3B /* Attribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Attribute.swift; path = common/Attribute.swift; sourceTree = ""; }; + C05082201DFA72F700D39B3B /* AttributeName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttributeName.swift; path = common/AttributeName.swift; sourceTree = ""; }; + C05082211DFA72F700D39B3B /* Ligatures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Ligatures.swift; path = common/Ligatures.swift; sourceTree = ""; }; + C05082221DFA72F700D39B3B /* NSAttributedString+SwiftyAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSAttributedString+SwiftyAttributes.swift"; path = "common/NSAttributedString+SwiftyAttributes.swift"; sourceTree = ""; }; + C05082231DFA72F700D39B3B /* NSMutableAttributedString+SwiftyAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSMutableAttributedString+SwiftyAttributes.swift"; path = "common/NSMutableAttributedString+SwiftyAttributes.swift"; sourceTree = ""; }; + C05082241DFA72F700D39B3B /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = common/Operators.swift; sourceTree = ""; }; + C05082251DFA72F700D39B3B /* String+SwiftyAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "String+SwiftyAttributes.swift"; path = "common/String+SwiftyAttributes.swift"; sourceTree = ""; }; + C05082261DFA72F700D39B3B /* TextEffect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TextEffect.swift; path = common/TextEffect.swift; sourceTree = ""; }; + C05082271DFA72F700D39B3B /* VerticalGlyphForm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VerticalGlyphForm.swift; path = common/VerticalGlyphForm.swift; sourceTree = ""; }; + C05082281DFA72F700D39B3B /* WritingDirection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WritingDirection.swift; path = common/WritingDirection.swift; sourceTree = ""; }; + C0782E361DEAB30800E1B99F /* ExampleApp-macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ExampleApp-macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + C0782E381DEAB30800E1B99F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + C0782E3A1DEAB30800E1B99F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + C0782E3C1DEAB30800E1B99F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C0782E3F1DEAB30800E1B99F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + C0782E411DEAB30800E1B99F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C08D04121DC39B5500575F98 /* NSMutableAttributedString_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSMutableAttributedString_Tests.swift; sourceTree = ""; }; C08D04141DC3B16A00575F98 /* NSAttributedString_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSAttributedString_Tests.swift; sourceTree = ""; }; + C09633DA1DD8016800059332 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C09633DC1DD8056000059332 /* SwiftyAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwiftyAttributes.h; sourceTree = ""; }; + C09633DE1DD8057A00059332 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C0D753FA1DC5C77E00BB9754 /* TextEffect_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEffect_Tests.swift; sourceTree = ""; }; C0D753FC1DC5C88900BB9754 /* Attribute_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Attribute_Tests.swift; sourceTree = ""; }; - C0E2114A1D9EC5C000623F02 /* SwiftyAttributes.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyAttributes.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C0E2114D1D9EC5C000623F02 /* SwiftyAttributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftyAttributes.h; sourceTree = ""; }; - C0E2114E1D9EC5C000623F02 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C0E211531D9EC5C000623F02 /* SwiftyAttributesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftyAttributesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + C0DB42EB1DDED3500093A6FA /* NSAttributedString+macOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+macOS.swift"; sourceTree = ""; }; + C0E1C94B1DD319D50068E85C /* SwiftyAttributes.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyAttributes.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C0E1C9531DD319D50068E85C /* SwiftyAttributesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftyAttributesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C0E211581D9EC5C000623F02 /* SwiftyAttributes_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftyAttributes_Tests.swift; sourceTree = ""; }; - C0E2115A1D9EC5C000623F02 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C0F001751DDD8EA5009AD8E0 /* SpellingState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpellingState.swift; sourceTree = ""; }; + C0F96A021DEDE1D300D039A4 /* VerticalGlyphForm_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalGlyphForm_Tests.swift; sourceTree = ""; }; + C0F96A041DEDE23200D039A4 /* String+macOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+macOS.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -82,18 +124,25 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - C0E211461D9EC5C000623F02 /* Frameworks */ = { + C0782E331DEAB30800E1B99F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C0E1C9471DD319D50068E85C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - C0E211501D9EC5C000623F02 /* Frameworks */ = { + C0E1C9501DD319D50068E85C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C0E211541D9EC5C000623F02 /* SwiftyAttributes.framework in Frameworks */, + C0E1C9541DD319D50068E85C /* SwiftyAttributes.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -113,12 +162,25 @@ path = "ExampleApp-iOS"; sourceTree = ""; }; + C0782E371DEAB30800E1B99F /* ExampleApp-macOS */ = { + isa = PBXGroup; + children = ( + C0782E381DEAB30800E1B99F /* AppDelegate.swift */, + C0782E3A1DEAB30800E1B99F /* ViewController.swift */, + C0782E3C1DEAB30800E1B99F /* Assets.xcassets */, + C0782E3E1DEAB30800E1B99F /* Main.storyboard */, + C0782E411DEAB30800E1B99F /* Info.plist */, + ); + path = "ExampleApp-macOS"; + sourceTree = ""; + }; C0E211401D9EC5C000623F02 = { isa = PBXGroup; children = ( C0E2114C1D9EC5C000623F02 /* SwiftyAttributes */, C0E211571D9EC5C000623F02 /* SwiftyAttributesTests */, C03658F81DC859D80051F06D /* ExampleApp-iOS */, + C0782E371DEAB30800E1B99F /* ExampleApp-macOS */, C0E2114B1D9EC5C000623F02 /* Products */, ); sourceTree = ""; @@ -126,9 +188,10 @@ C0E2114B1D9EC5C000623F02 /* Products */ = { isa = PBXGroup; children = ( - C0E2114A1D9EC5C000623F02 /* SwiftyAttributes.framework */, - C0E211531D9EC5C000623F02 /* SwiftyAttributesTests.xctest */, C03658F71DC859D80051F06D /* ExampleApp-iOS.app */, + C0E1C94B1DD319D50068E85C /* SwiftyAttributes.framework */, + C0E1C9531DD319D50068E85C /* SwiftyAttributesTests.xctest */, + C0782E361DEAB30800E1B99F /* ExampleApp-macOS.app */, ); name = Products; sourceTree = ""; @@ -136,17 +199,8 @@ C0E2114C1D9EC5C000623F02 /* SwiftyAttributes */ = { isa = PBXGroup; children = ( - C0127C3B1DB2D5490047DF5A /* Attribute.swift */, - C05C54F61DA61F4E007514C1 /* Ligatures.swift */, - C0335B5F1DC08409009F9B51 /* Operators.swift */, - C01C438C1DC472F000C49E5E /* TextEffect.swift */, - C00CF8F21DA6142500B6C1BB /* WritingDirection.swift */, - C0335B5D1DC083AE009F9B51 /* String+SwiftyAttributes.swift */, - C0335B5B1DC083A5009F9B51 /* NSAttributedString+SwiftyAttributes.swift */, - C0335B611DC086B3009F9B51 /* NSMutableAttributedString+SwiftyAttributes.swift */, - C0E2114D1D9EC5C000623F02 /* SwiftyAttributes.h */, - C0E2114E1D9EC5C000623F02 /* Info.plist */, - C03658EF1DC84B3F0051F06D /* Images.xcassets */, + C0F001791DDD972D009AD8E0 /* Supporting Files */, + C0F001631DDD8E56009AD8E0 /* Sources */, ); path = SwiftyAttributes; sourceTree = ""; @@ -155,25 +209,67 @@ isa = PBXGroup; children = ( C0D753FC1DC5C88900BB9754 /* Attribute_Tests.swift */, + C027C0CA1DEA452500953C09 /* Attribute+Sequence_Tests.swift */, C08D04121DC39B5500575F98 /* NSMutableAttributedString_Tests.swift */, C08D04141DC3B16A00575F98 /* NSAttributedString_Tests.swift */, C0E211581D9EC5C000623F02 /* SwiftyAttributes_Tests.swift */, C0335B631DC0877C009F9B51 /* WritingDirection_Tests.swift */, C0335B651DC087A3009F9B51 /* Operators_Tests.swift */, + C027C0C81DEA0A0100953C09 /* SpellingState_Tests.swift */, C0D753FA1DC5C77E00BB9754 /* TextEffect_Tests.swift */, - C0E2115A1D9EC5C000623F02 /* Info.plist */, + C09633DA1DD8016800059332 /* Info.plist */, + C0F96A021DEDE1D300D039A4 /* VerticalGlyphForm_Tests.swift */, ); path = SwiftyAttributesTests; sourceTree = ""; }; + C0F001631DDD8E56009AD8E0 /* Sources */ = { + isa = PBXGroup; + children = ( + C050821F1DFA72F700D39B3B /* Attribute.swift */, + C050821E1DFA72F700D39B3B /* Attribute+Sequence.swift */, + C05082201DFA72F700D39B3B /* AttributeName.swift */, + C05082211DFA72F700D39B3B /* Ligatures.swift */, + C05082221DFA72F700D39B3B /* NSAttributedString+SwiftyAttributes.swift */, + C05082231DFA72F700D39B3B /* NSMutableAttributedString+SwiftyAttributes.swift */, + C05082241DFA72F700D39B3B /* Operators.swift */, + C05082251DFA72F700D39B3B /* String+SwiftyAttributes.swift */, + C05082261DFA72F700D39B3B /* TextEffect.swift */, + C05082271DFA72F700D39B3B /* VerticalGlyphForm.swift */, + C05082281DFA72F700D39B3B /* WritingDirection.swift */, + C0F001661DDD8E56009AD8E0 /* macOS */, + ); + path = Sources; + sourceTree = ""; + }; + C0F001661DDD8E56009AD8E0 /* macOS */ = { + isa = PBXGroup; + children = ( + C0F001751DDD8EA5009AD8E0 /* SpellingState.swift */, + C0DB42EB1DDED3500093A6FA /* NSAttributedString+macOS.swift */, + C0F96A041DEDE23200D039A4 /* String+macOS.swift */, + ); + path = macOS; + sourceTree = ""; + }; + C0F001791DDD972D009AD8E0 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + C09633DE1DD8057A00059332 /* Info.plist */, + C09633DC1DD8056000059332 /* SwiftyAttributes.h */, + C03658EF1DC84B3F0051F06D /* Images.xcassets */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - C0E211471D9EC5C000623F02 /* Headers */ = { + C0E1C9481DD319D50068E85C /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - C0E2115B1D9EC5C000623F02 /* SwiftyAttributes.h in Headers */, + C09633E01DD806F600059332 /* SwiftyAttributes.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -191,46 +287,65 @@ buildRules = ( ); dependencies = ( + C0782E471DEABEED00E1B99F /* PBXTargetDependency */, ); name = "ExampleApp-iOS"; productName = "ExampleApp-iOS"; productReference = C03658F71DC859D80051F06D /* ExampleApp-iOS.app */; productType = "com.apple.product-type.application"; }; - C0E211491D9EC5C000623F02 /* SwiftyAttributes */ = { + C0782E351DEAB30800E1B99F /* ExampleApp-macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = C0782E441DEAB30800E1B99F /* Build configuration list for PBXNativeTarget "ExampleApp-macOS" */; + buildPhases = ( + C0782E321DEAB30800E1B99F /* Sources */, + C0782E331DEAB30800E1B99F /* Frameworks */, + C0782E341DEAB30800E1B99F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + C0782E491DEABEF100E1B99F /* PBXTargetDependency */, + ); + name = "ExampleApp-macOS"; + productName = "ExampleApp-macOS"; + productReference = C0782E361DEAB30800E1B99F /* ExampleApp-macOS.app */; + productType = "com.apple.product-type.application"; + }; + C0E1C94A1DD319D50068E85C /* SwiftyAttributes */ = { isa = PBXNativeTarget; - buildConfigurationList = C0E2115E1D9EC5C000623F02 /* Build configuration list for PBXNativeTarget "SwiftyAttributes" */; + buildConfigurationList = C0E1C95C1DD319D50068E85C /* Build configuration list for PBXNativeTarget "SwiftyAttributes" */; buildPhases = ( - C0E211451D9EC5C000623F02 /* Sources */, - C0E211461D9EC5C000623F02 /* Frameworks */, - C0E211471D9EC5C000623F02 /* Headers */, - C0E211481D9EC5C000623F02 /* Resources */, + C0E1C9461DD319D50068E85C /* Sources */, + C0E1C9471DD319D50068E85C /* Frameworks */, + C0E1C9481DD319D50068E85C /* Headers */, + C0E1C9491DD319D50068E85C /* Resources */, ); buildRules = ( ); dependencies = ( ); name = SwiftyAttributes; - productName = SwiftyAttributes; - productReference = C0E2114A1D9EC5C000623F02 /* SwiftyAttributes.framework */; + productName = "SwiftyAttributes-macOS"; + productReference = C0E1C94B1DD319D50068E85C /* SwiftyAttributes.framework */; productType = "com.apple.product-type.framework"; }; - C0E211521D9EC5C000623F02 /* SwiftyAttributesTests */ = { + C0E1C9521DD319D50068E85C /* SwiftyAttributesTests */ = { isa = PBXNativeTarget; - buildConfigurationList = C0E211611D9EC5C000623F02 /* Build configuration list for PBXNativeTarget "SwiftyAttributesTests" */; + buildConfigurationList = C0E1C95F1DD319D50068E85C /* Build configuration list for PBXNativeTarget "SwiftyAttributesTests" */; buildPhases = ( - C0E2114F1D9EC5C000623F02 /* Sources */, - C0E211501D9EC5C000623F02 /* Frameworks */, - C0E211511D9EC5C000623F02 /* Resources */, + C0E1C94F1DD319D50068E85C /* Sources */, + C0E1C9501DD319D50068E85C /* Frameworks */, + C0E1C9511DD319D50068E85C /* Resources */, ); buildRules = ( ); dependencies = ( - C0E211561D9EC5C000623F02 /* PBXTargetDependency */, + C0E1C9561DD319D50068E85C /* PBXTargetDependency */, ); name = SwiftyAttributesTests; - productName = SwiftyAttributesTests; - productReference = C0E211531D9EC5C000623F02 /* SwiftyAttributesTests.xctest */; + productName = "SwiftyAttributes-macOSTests"; + productReference = C0E1C9531DD319D50068E85C /* SwiftyAttributesTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ @@ -239,7 +354,7 @@ C0E211411D9EC5C000623F02 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0800; + LastSwiftUpdateCheck = 0810; LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Eddie Kaiger"; TargetAttributes = { @@ -248,16 +363,19 @@ DevelopmentTeam = 5KT4ZVPMF8; ProvisioningStyle = Automatic; }; - C0E211491D9EC5C000623F02 = { - CreatedOnToolsVersion = 8.0; - DevelopmentTeam = 5KT4ZVPMF8; - LastSwiftMigration = 0800; + C0782E351DEAB30800E1B99F = { + CreatedOnToolsVersion = 8.1; ProvisioningStyle = Automatic; }; - C0E211521D9EC5C000623F02 = { - CreatedOnToolsVersion = 8.0; + C0E1C94A1DD319D50068E85C = { + CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 0810; + ProvisioningStyle = Manual; + }; + C0E1C9521DD319D50068E85C = { + CreatedOnToolsVersion = 8.1; DevelopmentTeam = 5KT4ZVPMF8; - LastSwiftMigration = 0800; + LastSwiftMigration = 0810; ProvisioningStyle = Automatic; }; }; @@ -275,9 +393,10 @@ projectDirPath = ""; projectRoot = ""; targets = ( - C0E211491D9EC5C000623F02 /* SwiftyAttributes */, - C0E211521D9EC5C000623F02 /* SwiftyAttributesTests */, + C0E1C94A1DD319D50068E85C /* SwiftyAttributes */, + C0E1C9521DD319D50068E85C /* SwiftyAttributesTests */, C03658F61DC859D80051F06D /* ExampleApp-iOS */, + C0782E351DEAB30800E1B99F /* ExampleApp-macOS */, ); }; /* End PBXProject section */ @@ -294,18 +413,27 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - C0E211481D9EC5C000623F02 /* Resources */ = { + C0782E341DEAB30800E1B99F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + C0782E3D1DEAB30800E1B99F /* Assets.xcassets in Resources */, + C0782E401DEAB30800E1B99F /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - C0E211511D9EC5C000623F02 /* Resources */ = { + C0E1C9491DD319D50068E85C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - C03658F21DC84CCA0051F06D /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C0E1C9511DD319D50068E85C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C0E1C99C1DD31C640068E85C /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -321,42 +449,70 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - C0E211451D9EC5C000623F02 /* Sources */ = { + C0782E321DEAB30800E1B99F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C0782E3B1DEAB30800E1B99F /* ViewController.swift in Sources */, + C0782E391DEAB30800E1B99F /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C0E1C9461DD319D50068E85C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C0335B5C1DC083A5009F9B51 /* NSAttributedString+SwiftyAttributes.swift in Sources */, - C00CF8F31DA6142500B6C1BB /* WritingDirection.swift in Sources */, - C0335B601DC08409009F9B51 /* Operators.swift in Sources */, - C05C54F71DA61F4E007514C1 /* Ligatures.swift in Sources */, - C0127C3C1DB2D5490047DF5A /* Attribute.swift in Sources */, - C01C438D1DC472F000C49E5E /* TextEffect.swift in Sources */, - C0335B5E1DC083AE009F9B51 /* String+SwiftyAttributes.swift in Sources */, - C0335B621DC086B3009F9B51 /* NSMutableAttributedString+SwiftyAttributes.swift in Sources */, + C050822A1DFA72F700D39B3B /* Attribute.swift in Sources */, + C050822F1DFA72F700D39B3B /* Operators.swift in Sources */, + C050822E1DFA72F700D39B3B /* NSMutableAttributedString+SwiftyAttributes.swift in Sources */, + C050822B1DFA72F700D39B3B /* AttributeName.swift in Sources */, + C05082331DFA72F700D39B3B /* WritingDirection.swift in Sources */, + C050822C1DFA72F700D39B3B /* Ligatures.swift in Sources */, + C05082311DFA72F700D39B3B /* TextEffect.swift in Sources */, + C05082301DFA72F700D39B3B /* String+SwiftyAttributes.swift in Sources */, + C0DB42EC1DDED3500093A6FA /* NSAttributedString+macOS.swift in Sources */, + C05082321DFA72F700D39B3B /* VerticalGlyphForm.swift in Sources */, + C050822D1DFA72F700D39B3B /* NSAttributedString+SwiftyAttributes.swift in Sources */, + C0F96A051DEDE23200D039A4 /* String+macOS.swift in Sources */, + C0F001761DDD8EA5009AD8E0 /* SpellingState.swift in Sources */, + C05082291DFA72F700D39B3B /* Attribute+Sequence.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - C0E2114F1D9EC5C000623F02 /* Sources */ = { + C0E1C94F1DD319D50068E85C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C0335B641DC0877C009F9B51 /* WritingDirection_Tests.swift in Sources */, - C0D753FB1DC5C77E00BB9754 /* TextEffect_Tests.swift in Sources */, - C08D04131DC39B5500575F98 /* NSMutableAttributedString_Tests.swift in Sources */, - C0D753FD1DC5C88900BB9754 /* Attribute_Tests.swift in Sources */, - C0E211591D9EC5C000623F02 /* SwiftyAttributes_Tests.swift in Sources */, - C0335B661DC087A3009F9B51 /* Operators_Tests.swift in Sources */, - C08D04151DC3B16A00575F98 /* NSAttributedString_Tests.swift in Sources */, + C0E1C96E1DD31A0D0068E85C /* WritingDirection_Tests.swift in Sources */, + C0E1C96B1DD31A0D0068E85C /* NSMutableAttributedString_Tests.swift in Sources */, + C0E1C96D1DD31A0D0068E85C /* SwiftyAttributes_Tests.swift in Sources */, + C0E1C96A1DD31A0D0068E85C /* Attribute_Tests.swift in Sources */, + C0E1C9701DD31A0D0068E85C /* TextEffect_Tests.swift in Sources */, + C027C0C91DEA0A0100953C09 /* SpellingState_Tests.swift in Sources */, + C0F96A031DEDE1D300D039A4 /* VerticalGlyphForm_Tests.swift in Sources */, + C027C0CB1DEA452500953C09 /* Attribute+Sequence_Tests.swift in Sources */, + C0E1C96F1DD31A0D0068E85C /* Operators_Tests.swift in Sources */, + C0E1C96C1DD31A0D0068E85C /* NSAttributedString_Tests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - C0E211561D9EC5C000623F02 /* PBXTargetDependency */ = { + C0782E471DEABEED00E1B99F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C0E1C94A1DD319D50068E85C /* SwiftyAttributes */; + targetProxy = C0782E461DEABEED00E1B99F /* PBXContainerItemProxy */; + }; + C0782E491DEABEF100E1B99F /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = C0E211491D9EC5C000623F02 /* SwiftyAttributes */; - targetProxy = C0E211551D9EC5C000623F02 /* PBXContainerItemProxy */; + target = C0E1C94A1DD319D50068E85C /* SwiftyAttributes */; + targetProxy = C0782E481DEABEF100E1B99F /* PBXContainerItemProxy */; + }; + C0E1C9561DD319D50068E85C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C0E1C94A1DD319D50068E85C /* SwiftyAttributes */; + targetProxy = C0E1C9551DD319D50068E85C /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -377,6 +533,14 @@ name = LaunchScreen.storyboard; sourceTree = ""; }; + C0782E3E1DEAB30800E1B99F /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + C0782E3F1DEAB30800E1B99F /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -384,13 +548,18 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEVELOPMENT_TEAM = 5KT4ZVPMF8; INFOPLIST_FILE = "ExampleApp-iOS/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.eddiekaiger.ExampleApp-iOS"; PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_VERSION = 3.0.1; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -398,13 +567,118 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEVELOPMENT_TEAM = 5KT4ZVPMF8; INFOPLIST_FILE = "ExampleApp-iOS/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.eddiekaiger.ExampleApp-iOS"; PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_VERSION = 3.0.1; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + C0782E421DEAB30800E1B99F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "ExampleApp-macOS/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "com.eddiekaiger.ExampleApp-macOS"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + C0782E431DEAB30800E1B99F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "ExampleApp-macOS/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "com.eddiekaiger.ExampleApp-macOS"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + C0E1C95D1DD319D50068E85C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = SwiftyAttributes/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.eddiekaiger.SwiftyAttributes; + PRODUCT_BUNDLE_PACKAGE_TYPE = FMWK; + PRODUCT_NAME = SwiftyAttributes; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + C0E1C95E1DD319D50068E85C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = SwiftyAttributes/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.eddiekaiger.SwiftyAttributes; + PRODUCT_BUNDLE_PACKAGE_TYPE = FMWK; + PRODUCT_NAME = SwiftyAttributes; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + C0E1C9601DD319D50068E85C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = SwiftyAttributes/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks @loader_path/Frameworks @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.eddiekaiger.SwiftyAttributesTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + C0E1C9611DD319D50068E85C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = SwiftyAttributes/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks @loader_path/Frameworks @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.eddiekaiger.SwiftyAttributesTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -430,7 +704,6 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; @@ -451,14 +724,18 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; + PRODUCT_BUNDLE_PACKAGE_TYPE = BNDL; + SUPPORTED_PLATFORMS = "watchsimulator watchos appletvos appletvsimulator iphoneos iphonesimulator macosx"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,3,4"; + TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; @@ -484,7 +761,6 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -499,80 +775,17 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; + PRODUCT_BUNDLE_PACKAGE_TYPE = BNDL; + SUPPORTED_PLATFORMS = "watchsimulator watchos appletvos appletvsimulator iphoneos iphonesimulator macosx"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,3,4"; + TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - C0E2115F1D9EC5C000623F02 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 5KT4ZVPMF8; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = SwiftyAttributes/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.eddiekaiger.SwiftyAttributes; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; - }; - name = Debug; - }; - C0E211601D9EC5C000623F02 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 5KT4ZVPMF8; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = SwiftyAttributes/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.eddiekaiger.SwiftyAttributes; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; - }; - name = Release; - }; - C0E211621D9EC5C000623F02 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - DEVELOPMENT_TEAM = 5KT4ZVPMF8; - INFOPLIST_FILE = SwiftyAttributesTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.eddiekaiger.SwiftyAttributesTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; - }; - name = Debug; - }; - C0E211631D9EC5C000623F02 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - DEVELOPMENT_TEAM = 5KT4ZVPMF8; - INFOPLIST_FILE = SwiftyAttributesTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.eddiekaiger.SwiftyAttributesTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Release; }; @@ -588,29 +801,38 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - C0E211441D9EC5C000623F02 /* Build configuration list for PBXProject "SwiftyAttributes" */ = { + C0782E441DEAB30800E1B99F /* Build configuration list for PBXNativeTarget "ExampleApp-macOS" */ = { isa = XCConfigurationList; buildConfigurations = ( - C0E2115C1D9EC5C000623F02 /* Debug */, - C0E2115D1D9EC5C000623F02 /* Release */, + C0782E421DEAB30800E1B99F /* Debug */, + C0782E431DEAB30800E1B99F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C0E1C95C1DD319D50068E85C /* Build configuration list for PBXNativeTarget "SwiftyAttributes" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C0E1C95D1DD319D50068E85C /* Debug */, + C0E1C95E1DD319D50068E85C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - C0E2115E1D9EC5C000623F02 /* Build configuration list for PBXNativeTarget "SwiftyAttributes" */ = { + C0E1C95F1DD319D50068E85C /* Build configuration list for PBXNativeTarget "SwiftyAttributesTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - C0E2115F1D9EC5C000623F02 /* Debug */, - C0E211601D9EC5C000623F02 /* Release */, + C0E1C9601DD319D50068E85C /* Debug */, + C0E1C9611DD319D50068E85C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - C0E211611D9EC5C000623F02 /* Build configuration list for PBXNativeTarget "SwiftyAttributesTests" */ = { + C0E211441D9EC5C000623F02 /* Build configuration list for PBXProject "SwiftyAttributes" */ = { isa = XCConfigurationList; buildConfigurations = ( - C0E211621D9EC5C000623F02 /* Debug */, - C0E211631D9EC5C000623F02 /* Release */, + C0E2115C1D9EC5C000623F02 /* Debug */, + C0E2115D1D9EC5C000623F02 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/ExampleApp-iOS.xcscheme b/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/ExampleApp-iOS.xcscheme new file mode 100644 index 0000000..5e6acd5 --- /dev/null +++ b/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/ExampleApp-iOS.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/ExampleApp-macOS.xcscheme b/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/ExampleApp-macOS.xcscheme new file mode 100644 index 0000000..d827b7a --- /dev/null +++ b/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/ExampleApp-macOS.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/SwiftyAttributes.xcscheme b/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/SwiftyAttributes.xcscheme index b561349..c19013a 100644 --- a/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/SwiftyAttributes.xcscheme +++ b/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/SwiftyAttributes.xcscheme @@ -1,6 +1,6 @@ @@ -26,13 +26,14 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> @@ -42,7 +43,7 @@ @@ -64,7 +65,7 @@ @@ -82,7 +83,7 @@ diff --git a/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/SwiftyAttributesTests.xcscheme b/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/SwiftyAttributesTests.xcscheme index 383e480..c8d6359 100644 --- a/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/SwiftyAttributesTests.xcscheme +++ b/SwiftyAttributes.xcodeproj/xcshareddata/xcschemes/SwiftyAttributesTests.xcscheme @@ -1,7 +1,7 @@ + LastUpgradeVersion = "0810" + version = "1.7"> @@ -10,18 +10,21 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES"> + + diff --git a/SwiftyAttributes/Attribute.swift b/SwiftyAttributes/Attribute.swift deleted file mode 100644 index 1cefbb9..0000000 --- a/SwiftyAttributes/Attribute.swift +++ /dev/null @@ -1,250 +0,0 @@ -// -// Attribute.swift -// SwiftyAttributes -// -// Created by Eddie Kaiger on 10/15/16. -// Copyright © 2016 Eddie Kaiger. All rights reserved. -// - -import Foundation - -public typealias UnderlineStyle = NSUnderlineStyle -public typealias StrikethroughStyle = NSUnderlineStyle - -/** - Represents attributes that can be applied to NSAttributedStrings. - */ -public enum Attribute { - - /// Attachment attribute that allows items like images to be inserted into text. - case attachment(NSTextAttachment) - - /// Value indicating the character's offset from the baseline, in points. - case baselineOffset(Double) - - /// The background color of the attributed string. - case backgroundColor(UIColor) - - /// Value indicating the log of the expansion factor to be applied to glyphs. - case expansion(Double) - - /// The font of the attributed string. - case font(UIFont) - - /// Specifies the number of points by which to adjust kern-pair characters. Kerning prevents unwanted space from occurring between specific characters and depends on the font. The value 0 means kerning is disabled (default). - case kern(Double) - - /// Ligatures cause specific character combinations to be rendered using a single custom glyph that corresponds to those characters. See `Ligatures` for values. - case ligatures(Ligatures) - - /// A URL link to attach to the attributed string. - case link(URL) - - /// A value indicating the skew to be applied to glyphs. - case obliqueness(Double) - - /// An `NSParagraphStyle` to be applied to the attributed string. - case paragraphStyle(NSParagraphStyle) - - /// A shadow to be applied to the characters. - case shadow(NSShadow) - - /// The color of the stroke (border) around the characters. - case strokeColor(UIColor) - - /// The width/thickness of the stroke (border) around the characters. - case strokeWidth(Double) - - /// The color of the strikethrough. - case strikethroughColor(UIColor) - - /// The style of the strikethrough. - case strikethroughStyle(StrikethroughStyle) - - /// The text color. - case textColor(UIColor) - - /// The text effect to apply. See `TextEffect` for possible values. - case textEffect(TextEffect) - - /// The color of the underline. - case underlineColor(UIColor) - - /// The style of the underline. - case underlineStyle(UnderlineStyle) - - /// The writing directions to apply to the attributed string. See `WritingDirection` for values. Only available on iOS 9.0+. - case writingDirections([WritingDirection]) - - init(name: Attribute.Name, value: Any) { - func validate(_ val: Any) -> Type { - return val as! Type - } - - switch name { - case .attachment: self = .attachment(validate(value)) - case .baselineOffset: self = .baselineOffset(validate(value)) - case .backgroundColor: self = .backgroundColor(validate(value)) - case .expansion: self = .expansion(validate(value)) - case .font: self = .font(validate(value)) - case .kern: self = .kern(validate(value)) - case .ligature: self = .ligatures(validate(value)) - case .link: self = .link(validate(value)) - case .obliqueness: self = .obliqueness(validate(value)) - case .paragraphStyle: self = .paragraphStyle(validate(value)) - case .shadow: self = .shadow(validate(value)) - case .strokeColor: self = .strokeColor(validate(value)) - case .strokeWidth: self = .strokeWidth(validate(value)) - case .strikethroughColor: self = .strikethroughColor(validate(value)) - case .strikethroughStyle: self = .strikethroughStyle(validate(value)) - case .textColor: self = .textColor(validate(value)) - case .textEffect: self = .textEffect(validate(value)) - case .underlineColor: self = .underlineColor(validate(value)) - case .underlineStyle: self = .underlineStyle(validate(value)) - case .writingDirection: self = .writingDirections(validate(value)) - } - } - - /// The key name corresponding to the attribute. - public var keyName: String { - let name: Attribute.Name - switch self { - case .attachment(_): name = .attachment - case .baselineOffset(_): name = .baselineOffset - case .backgroundColor(_): name = .backgroundColor - case .expansion(_): name = .expansion - case .font(_): name = .font - case .kern(_): name = .kern - case .ligatures(_): name = .ligature - case .link(_): name = .link - case .obliqueness(_): name = .obliqueness - case .paragraphStyle(_): name = .paragraphStyle - case .shadow(_): name = .shadow - case .strokeColor(_): name = .strokeColor - case .strokeWidth(_): name = .strokeWidth - case .strikethroughColor(_): name = .strikethroughColor - case .strikethroughStyle(_): name = .strikethroughStyle - case .textColor(_): name = .textColor - case .textEffect(_): name = .textEffect - case .underlineColor(_): name = .underlineColor - case .underlineStyle(_): name = .underlineStyle - case .writingDirections(_): name = .writingDirection - } - return name.rawValue - } - - // Convenience getter variable for the associated value of the attribute. See each case to determine the return type. - public var value: Any { - switch self { - case .attachment(let attachment): return attachment - case .baselineOffset(let offset): return offset - case .backgroundColor(let color): return color - case .expansion(let expansion): return expansion - case .font(let font): return font - case .kern(let kern): return kern - case .ligatures(let ligatures): return ligatures - case .link(let link): return link - case .obliqueness(let value): return value - case .paragraphStyle(let style): return style - case .shadow(let shadow): return shadow - case .strokeColor(let color): return color - case .strokeWidth(let width): return width - case .strikethroughColor(let color): return color - case .strikethroughStyle(let style): return style - case .textColor(let color): return color - case .textEffect(let effect): return effect - case .underlineColor(let color): return color - case .underlineStyle(let style): return style - case .writingDirections(let directions): return directions - } - } - - var foundationValue: Any { - switch self { - case .ligatures(let ligatures): return ligatures.rawValue - case .strikethroughStyle(let style): return NSNumber(value: style.rawValue) - case .textEffect(let effect): return effect.rawValue - case .underlineStyle(let style): return NSNumber(value: style.rawValue) - case .writingDirections(let directions): return directions.map { $0.rawValue } - default: return value - } - } - - /** - An enum that corresponds to `Attribute`, mapping attributes to their respective names. - */ - public enum Name: RawRepresentable { - case attachment - case baselineOffset - case backgroundColor - case expansion - case font - case kern - case ligature - case link - case obliqueness - case paragraphStyle - case shadow - case strokeColor - case strokeWidth - case strikethroughColor - case strikethroughStyle - case textColor - case textEffect - case underlineColor - case underlineStyle - case writingDirection - - public init?(rawValue: String) { - switch rawValue { - case NSAttachmentAttributeName: self = .attachment - case NSBaselineOffsetAttributeName: self = .baselineOffset - case NSBackgroundColorAttributeName: self = .backgroundColor - case NSExpansionAttributeName: self = .expansion - case NSFontAttributeName: self = .font - case NSKernAttributeName: self = .kern - case NSLigatureAttributeName: self = .ligature - case NSLinkAttributeName: self = .link - case NSObliquenessAttributeName: self = .obliqueness - case NSParagraphStyleAttributeName: self = .paragraphStyle - case NSShadowAttributeName: self = .shadow - case NSStrokeColorAttributeName: self = .strokeColor - case NSStrokeWidthAttributeName: self = .strokeWidth - case NSStrikethroughColorAttributeName: self = .strikethroughColor - case NSStrikethroughStyleAttributeName: self = .strikethroughStyle - case NSForegroundColorAttributeName: self = .textColor - case NSTextEffectAttributeName: self = .textEffect - case NSUnderlineColorAttributeName: self = .underlineColor - case NSUnderlineStyleAttributeName: self = .underlineStyle - case NSWritingDirectionAttributeName: self = .writingDirection - default: return nil - } - } - - public var rawValue: String { - switch self { - case .attachment: return NSAttachmentAttributeName - case .baselineOffset: return NSBaselineOffsetAttributeName - case .backgroundColor: return NSBackgroundColorAttributeName - case .expansion: return NSExpansionAttributeName - case .font: return NSFontAttributeName - case .kern: return NSKernAttributeName - case .ligature: return NSLigatureAttributeName - case .link: return NSLinkAttributeName - case .obliqueness: return NSObliquenessAttributeName - case .paragraphStyle: return NSParagraphStyleAttributeName - case .shadow: return NSShadowAttributeName - case .strokeColor: return NSStrokeColorAttributeName - case .strokeWidth: return NSStrokeWidthAttributeName - case .strikethroughColor: return NSStrikethroughColorAttributeName - case .strikethroughStyle: return NSStrikethroughStyleAttributeName - case .textColor: return NSForegroundColorAttributeName - case .textEffect: return NSTextEffectAttributeName - case .underlineColor: return NSUnderlineColorAttributeName - case .underlineStyle: return NSUnderlineStyleAttributeName - case .writingDirection: return NSWritingDirectionAttributeName - } - - } - } -} diff --git a/SwiftyAttributes/Info.plist b/SwiftyAttributes/Info.plist index ee73227..d0cdb4b 100644 --- a/SwiftyAttributes/Info.plist +++ b/SwiftyAttributes/Info.plist @@ -13,12 +13,14 @@ CFBundleName $(PRODUCT_NAME) CFBundlePackageType - FMWK + BNDL CFBundleShortVersionString - 3.0.0 + 3.1.0 + CFBundleSignature + ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - + NSHumanReadableCopyright + Copyright © 2016 Eddie Kaiger. All rights reserved. diff --git a/SwiftyAttributes/Sources/common/Attribute+Sequence.swift b/SwiftyAttributes/Sources/common/Attribute+Sequence.swift new file mode 100644 index 0000000..c8d12ba --- /dev/null +++ b/SwiftyAttributes/Sources/common/Attribute+Sequence.swift @@ -0,0 +1,41 @@ +// +// AttributeConversions.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 11/23/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +/** + An extension on dictionaries that allows us to convert a Foundation-based dictionary of attributes to an array of `Attribute`s. + + A Sequence with an iterator of (String, Any) is equivalent to [String: Any] + This is a simple syntactic workaround since we can't write "extension Dictionary where Key == String". Thanks Swift :) + */ +extension Sequence where Iterator.Element == (key: String, value: Any) { + + /// Returns an array of `Attribute`s converted from the dictionary of attributes. Use this whenever you want to convert [String: Any] to [Attribute]. + public var swiftyAttributes: [Attribute] { + return flatMap { name, value in + if let attrName = Attribute.Name(rawValue: name) { + return Attribute(name: attrName, foundationValue: value) + } else { + return nil + } + } + } + +} + +extension Sequence where Iterator.Element == Attribute { + + /// Returns the attribute dictionary required by Foundation's API for attributed strings. Use this whenever you need to convert [Attribute] to [String: Any]. + public var foundationAttributes: [String: Any] { + return reduce([String: Any]()) { dictionary, attribute in + var dict = dictionary + dict[attribute.keyName] = attribute.foundationValue + return dict + } + } + +} diff --git a/SwiftyAttributes/Sources/common/Attribute.swift b/SwiftyAttributes/Sources/common/Attribute.swift new file mode 100644 index 0000000..3149dd1 --- /dev/null +++ b/SwiftyAttributes/Sources/common/Attribute.swift @@ -0,0 +1,330 @@ +// +// Attribute.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 10/15/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +#if os(macOS) + import AppKit + public typealias Color = NSColor + public typealias Font = NSFont + public typealias Cursor = NSCursor + public typealias TextAlternatives = NSTextAlternatives +#else + import UIKit + public typealias Color = UIColor + public typealias Font = UIFont +#endif + +public typealias UnderlineStyle = NSUnderlineStyle +public typealias StrikethroughStyle = NSUnderlineStyle +public typealias ParagraphStyle = NSParagraphStyle + +#if os(watchOS) +#else +public typealias Shadow = NSShadow +public typealias TextAttachment = NSTextAttachment +#endif + +/** + Represents attributes that can be applied to NSAttributedStrings. + */ +public enum Attribute { + + #if os(watchOS) + #else + /// Attachment attribute that allows items like images to be inserted into text. + case attachment(TextAttachment) + #endif + + /// Value indicating the character's offset from the baseline, in points. + case baselineOffset(Double) + + /// The background color of the attributed string. + case backgroundColor(Color) + + #if os(macOS) + /// The cursor object associated with the attributed string. + case cursor(Cursor) + #endif + + /// Value indicating the log of the expansion factor to be applied to glyphs. + case expansion(Double) + + /// The font of the attributed string. + case font(Font) + + /// Specifies the number of points by which to adjust kern-pair characters. Kerning prevents unwanted space from occurring between specific characters and depends on the font. The value 0 means kerning is disabled (default). + case kern(Double) + + /// Ligatures cause specific character combinations to be rendered using a single custom glyph that corresponds to those characters. See `Ligatures` for values. + case ligatures(Ligatures) + + /// A URL link to attach to the attributed string. + case link(URL) + + #if os(macOS) + /// The index in marked text indicating clause segments. + case markedClauseSegment(Int) + #endif + + /// A value indicating the skew to be applied to glyphs. + case obliqueness(Double) + + /// An `NSParagraphStyle` to be applied to the attributed string. + case paragraphStyle(ParagraphStyle) + + #if os(watchOS) + #else + /// A shadow to be applied to the characters. + case shadow(Shadow) + #endif + + #if os(macOS) + /// A state indicating a spelling or grammar error. See `SpellingState` for possible values. + case spellingState(SpellingState) + #endif + + /// The color of the stroke (border) around the characters. + case strokeColor(Color) + + /// The width/thickness of the stroke (border) around the characters. + case strokeWidth(Double) + + /// The color of the strikethrough. + case strikethroughColor(Color) + + /// The style of the strikethrough. + case strikethroughStyle(StrikethroughStyle) + + #if os(macOS) + /// The superscript attribute. + case superscript(Int) + + /// The object representing alternatives for a string that may be presented to the user. + case textAlternatives(TextAlternatives) + #endif + + /// The text color. + case textColor(Color) + + /// The text effect to apply. See `TextEffect` for possible values. + case textEffect(TextEffect) + + #if os(macOS) + /// The text of the tooltip. + case toolTip(String) + #endif + + /// The color of the underline. + case underlineColor(Color) + + /// The style of the underline. + case underlineStyle(UnderlineStyle) + + /// The vertical glyph form (horizontal or vertical text). See `VerticalGlyphForm` for details. + case verticalGlyphForm(VerticalGlyphForm) + + /// The writing directions to apply to the attributed string. See `WritingDirection` for values. Only available on iOS 9.0+. + case writingDirections([WritingDirection]) + + init(name: Attribute.Name, foundationValue: Any) { + func validate(_ val: Any) -> Type { + assert(val is Type, "Attribute with name \(name.rawValue) must have a value of type \(Type.self)") + return val as! Type + } + + func validateDouble(_ val: Any) -> Double { + assert(val is NSNumber, "Attribute with name \(name.rawValue) must have a value that is castable to NSNumber") + return (val as! NSNumber).doubleValue + } + + var ret: Attribute! + + // Bug in Swift prevents us from putting directives inside switch statements (https://bugs.swift.org/browse/SR-2) + + #if os(watchOS) + #else + switch name { + case .attachment: ret = .attachment(validate(foundationValue)) + case .shadow: ret = .shadow(validate(foundationValue)) + default: break + } + #endif + + #if os(macOS) + switch name { + case .cursor: ret = .cursor(validate(foundationValue)) + case .markedClauseSegment: ret = .markedClauseSegment(validate(foundationValue)) + case .spellingState: ret = .spellingState(SpellingState(rawValue: validate(foundationValue))!) + case .superscript: ret = .superscript(validate(foundationValue)) + case .textAlternatives: ret = .textAlternatives(validate(foundationValue)) + case .toolTip: ret = .toolTip(validate(foundationValue)) + default: break + } + #endif + + switch name { + case .baselineOffset: ret = .baselineOffset(validateDouble(foundationValue)) + case .backgroundColor: ret = .backgroundColor(validate(foundationValue)) + case .expansion: ret = .expansion(validateDouble(foundationValue)) + case .font: ret = .font(validate(foundationValue)) + case .kern: ret = .kern(validateDouble(foundationValue)) + case .ligature: ret = .ligatures(Ligatures(rawValue: validate(foundationValue))!) + case .link: ret = .link(validate(foundationValue)) + case .obliqueness: ret = .obliqueness(validateDouble(foundationValue)) + case .paragraphStyle: ret = .paragraphStyle(validate(foundationValue)) + case .strokeColor: ret = .strokeColor(validate(foundationValue)) + case .strokeWidth: ret = .strokeWidth(validateDouble(foundationValue)) + case .strikethroughColor: ret = .strikethroughColor(validate(foundationValue)) + case .strikethroughStyle: ret = .strikethroughStyle(StrikethroughStyle(rawValue: validate(foundationValue))!) + case .textColor: ret = .textColor(validate(foundationValue)) + case .textEffect: ret = .textEffect(TextEffect(rawValue: validate(foundationValue))!) + case .underlineColor: ret = .underlineColor(validate(foundationValue)) + case .underlineStyle: ret = .underlineStyle(UnderlineStyle(rawValue: validate(foundationValue))!) + case .verticalGlyphForm: ret = .verticalGlyphForm(VerticalGlyphForm(rawValue: validate(foundationValue))!) + case .writingDirection: + let values: [Int] = validate(foundationValue) + ret = .writingDirections(values.flatMap(WritingDirection.init)) + default: break + } + + self = ret + } + + /// The key name corresponding to the attribute. + public var keyName: String { + + var name: Attribute.Name! + + // Bug in Swift prevents us from putting directives inside switch statements (https://bugs.swift.org/browse/SR-2) + + #if os(watchOS) + #else + switch self { + case .attachment(_): name = .attachment + case .shadow(_): name = .shadow + default: break + } + #endif + + #if os(macOS) + switch self { + case .cursor(_): name = .cursor + case .markedClauseSegment(_): name = .markedClauseSegment + case .spellingState(_): name = .spellingState + case .superscript(_): name = .superscript + case .textAlternatives(_): name = .textAlternatives + case .toolTip(_): name = .toolTip + default: break + } + #endif + + switch self { + case .baselineOffset(_): name = .baselineOffset + case .backgroundColor(_): name = .backgroundColor + case .expansion(_): name = .expansion + case .font(_): name = .font + case .kern(_): name = .kern + case .ligatures(_): name = .ligature + case .link(_): name = .link + case .obliqueness(_): name = .obliqueness + case .paragraphStyle(_): name = .paragraphStyle + case .strokeColor(_): name = .strokeColor + case .strokeWidth(_): name = .strokeWidth + case .strikethroughColor(_): name = .strikethroughColor + case .strikethroughStyle(_): name = .strikethroughStyle + case .textColor(_): name = .textColor + case .textEffect(_): name = .textEffect + case .underlineColor(_): name = .underlineColor + case .underlineStyle(_): name = .underlineStyle + case .writingDirections(_): name = .writingDirection + case .verticalGlyphForm(_): name = .verticalGlyphForm + default: break + } + + return name.rawValue + } + + // Convenience getter variable for the associated value of the attribute. See each case to determine the return type. + public var value: Any { + + var ret: Any! + + // Bug in Swift prevents us from putting directives inside switch statements (https://bugs.swift.org/browse/SR-2) + + #if os(watchOS) + #else + switch self { + case .attachment(let attachment): ret = attachment + case .shadow(let shadow): ret = shadow + default: break + } + #endif + + #if os(macOS) + switch self { + case .cursor(let cursor): ret = cursor + case .markedClauseSegment(let segment): ret = segment + case .spellingState(let state): ret = state + case .superscript(let superscript): ret = superscript + case .textAlternatives(let alternatives): ret = alternatives + case .toolTip(let text): ret = text + default: break + } + #endif + + switch self { + case .baselineOffset(let offset): ret = offset + case .backgroundColor(let color): ret = color + case .expansion(let expansion): ret = expansion + case .font(let font): ret = font + case .kern(let kern): ret = kern + case .ligatures(let ligatures): ret = ligatures + case .link(let link): ret = link + case .obliqueness(let value): ret = value + case .paragraphStyle(let style): ret = style + case .strokeColor(let color): ret = color + case .strokeWidth(let width): ret = width + case .strikethroughColor(let color): ret = color + case .strikethroughStyle(let style): ret = style + case .textColor(let color): ret = color + case .textEffect(let effect): ret = effect + case .underlineColor(let color): ret = color + case .underlineStyle(let style): ret = style + case .verticalGlyphForm(let form): ret = form + case .writingDirections(let directions): ret = directions + default: break + } + + return ret + } + + /// The value that is passed into the original attribute dictionary of Foundation's API for NSAttributedStrings. Consists of basic types such as Int, Color, Font, etc. + public var foundationValue: Any { + #if os(macOS) + switch self { + case .spellingState(let state): return state.rawValue + default: break + } + #endif + + switch self { + case .ligatures(let ligatures): return ligatures.rawValue + case .strikethroughStyle(let style): return style.rawValue + case .textEffect(let effect): return effect.rawValue + case .underlineStyle(let style): return style.rawValue + case .writingDirections(let directions): return directions.map { $0.rawValue } + case .verticalGlyphForm(let form): return form.rawValue + default: return value + } + } +} + +extension Attribute: Equatable { } + +public func == (lhs: Attribute, rhs: Attribute) -> Bool { + return (lhs.foundationValue as? NSObject) == (rhs.foundationValue as? NSObject) +} diff --git a/SwiftyAttributes/Sources/common/AttributeName.swift b/SwiftyAttributes/Sources/common/AttributeName.swift new file mode 100644 index 0000000..37d8892 --- /dev/null +++ b/SwiftyAttributes/Sources/common/AttributeName.swift @@ -0,0 +1,181 @@ +// +// AttributeName.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 11/23/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +#if os(macOS) + import AppKit +#else + import UIKit +#endif + +extension Attribute { + + /** + An enum that corresponds to `Attribute`, mapping attributes to their respective names. + */ + public enum Name: RawRepresentable { + #if os(watchOS) + #else + case attachment + #endif + case baselineOffset + case backgroundColor + #if os(macOS) + case cursor + #endif + case expansion + case font + case kern + case ligature + case link + #if os(macOS) + case markedClauseSegment + #endif + case obliqueness + case paragraphStyle + #if os(watchOS) + #else + case shadow + #endif + #if os(macOS) + case spellingState + #endif + case strokeColor + case strokeWidth + case strikethroughColor + case strikethroughStyle + #if os(macOS) + case superscript + case textAlternatives + #endif + case textColor + case textEffect + #if os(macOS) + case toolTip + #endif + case underlineColor + case underlineStyle + case verticalGlyphForm + case writingDirection + + public init?(rawValue: String) { + + #if os(macOS) + switch rawValue { + case NSCursorAttributeName: + self = .cursor + return + case NSMarkedClauseSegmentAttributeName: + self = .markedClauseSegment + return + case NSSpellingStateAttributeName: + self = .spellingState + return + case NSSuperscriptAttributeName: + self = .superscript + return + case NSTextAlternativesAttributeName: + self = .textAlternatives + return + case NSToolTipAttributeName: + self = .toolTip + return + default: break + } + #endif + + switch rawValue { + case NSAttachmentAttributeName: + #if os(watchOS) + return nil + #else + self = .attachment + #endif + case NSBaselineOffsetAttributeName: self = .baselineOffset + case NSBackgroundColorAttributeName: self = .backgroundColor + case NSExpansionAttributeName: self = .expansion + case NSFontAttributeName: self = .font + case NSKernAttributeName: self = .kern + case NSLigatureAttributeName: self = .ligature + case NSLinkAttributeName: self = .link + case NSObliquenessAttributeName: self = .obliqueness + case NSParagraphStyleAttributeName: self = .paragraphStyle + case NSShadowAttributeName: + #if os(watchOS) + return nil + #else + self = .shadow + #endif + case NSStrokeColorAttributeName: self = .strokeColor + case NSStrokeWidthAttributeName: self = .strokeWidth + case NSStrikethroughColorAttributeName: self = .strikethroughColor + case NSStrikethroughStyleAttributeName: self = .strikethroughStyle + case NSForegroundColorAttributeName: self = .textColor + case NSTextEffectAttributeName: self = .textEffect + case NSUnderlineColorAttributeName: self = .underlineColor + case NSUnderlineStyleAttributeName: self = .underlineStyle + case NSVerticalGlyphFormAttributeName: self = .verticalGlyphForm + case NSWritingDirectionAttributeName: self = .writingDirection + default: return nil + } + } + + public var rawValue: String { + + var name: String! + + // Bug in Swift prevents us from putting directives inside switch statements (https://bugs.swift.org/browse/SR-2) + + #if os(watchOS) + #else + switch self { + case .attachment: name = NSAttachmentAttributeName + case .shadow: name = NSShadowAttributeName + default: break + } + #endif + + #if os(macOS) + switch self { + case .cursor: name = NSCursorAttributeName + case .markedClauseSegment: name = NSMarkedClauseSegmentAttributeName + case .spellingState: name = NSSpellingStateAttributeName + case .superscript: name = NSSuperscriptAttributeName + case .textAlternatives: name = NSTextAlternativesAttributeName + case .toolTip: name = NSToolTipAttributeName + default: break + } + #endif + + switch self { + case .baselineOffset: name = NSBaselineOffsetAttributeName + case .backgroundColor: name = NSBackgroundColorAttributeName + case .expansion: name = NSExpansionAttributeName + case .font: name = NSFontAttributeName + case .kern: name = NSKernAttributeName + case .ligature: name = NSLigatureAttributeName + case .link: name = NSLinkAttributeName + case .obliqueness: name = NSObliquenessAttributeName + case .paragraphStyle: name = NSParagraphStyleAttributeName + case .strokeColor: name = NSStrokeColorAttributeName + case .strokeWidth: name = NSStrokeWidthAttributeName + case .strikethroughColor: name = NSStrikethroughColorAttributeName + case .strikethroughStyle: name = NSStrikethroughStyleAttributeName + case .textColor: name = NSForegroundColorAttributeName + case .textEffect: name = NSTextEffectAttributeName + case .underlineColor: name = NSUnderlineColorAttributeName + case .underlineStyle: name = NSUnderlineStyleAttributeName + case .verticalGlyphForm: name = NSVerticalGlyphFormAttributeName + case .writingDirection: name = NSWritingDirectionAttributeName + default: break + } + + return name + } + } + +} diff --git a/SwiftyAttributes/Ligatures.swift b/SwiftyAttributes/Sources/common/Ligatures.swift similarity index 100% rename from SwiftyAttributes/Ligatures.swift rename to SwiftyAttributes/Sources/common/Ligatures.swift diff --git a/SwiftyAttributes/NSAttributedString+SwiftyAttributes.swift b/SwiftyAttributes/Sources/common/NSAttributedString+SwiftyAttributes.swift similarity index 63% rename from SwiftyAttributes/NSAttributedString+SwiftyAttributes.swift rename to SwiftyAttributes/Sources/common/NSAttributedString+SwiftyAttributes.swift index 0ba088d..2116d0e 100644 --- a/SwiftyAttributes/NSAttributedString+SwiftyAttributes.swift +++ b/SwiftyAttributes/Sources/common/NSAttributedString+SwiftyAttributes.swift @@ -71,24 +71,73 @@ extension NSAttributedString { - If the named attribute exists at `location`, upon return `range` contains a range over which the named attribute’s value applies. - If the named attribute does not exist at `location`, upon return `range` contains the range over which the attribute does not exist. - The range isn’t necessarily the maximum range covered by `attrName`, and its extent is implementation-dependent. If you need the maximum range, use attribute(_:at:longestEffectiveRange:in:). If you don't need this value, pass `nil`. + The range isn’t necessarily the maximum range covered by `attrName`, and its extent is implementation-dependent. + If you need the maximum range, use attribute(_:at:longestEffectiveRange:in:). If you don't need this value, pass `nil`. */ public func attribute(_ attrName: Attribute.Name, at location: Int, effectiveRange range: NSRangePointer? = nil) -> Attribute? { - if let attr = attribute(attrName.rawValue, at: location, effectiveRange: range) { - let attributeValue: Any - switch attrName { - case .ligature: attributeValue = Ligatures(rawValue: attr as! Int)! - case .strikethroughStyle: attributeValue = NSUnderlineStyle(rawValue: attr as! Int)! - case .textEffect: attributeValue = TextEffect(rawValue: attr as! String)! - case .underlineStyle: attributeValue = NSUnderlineStyle(rawValue: attr as! Int)! - case .writingDirection: attributeValue = (attr as! [Int]).map(WritingDirection.init) - default: attributeValue = attr - } - return Attribute(name: attrName, value: attributeValue) + if let attributeValue = attribute(attrName.rawValue, at: location, effectiveRange: range) { + return Attribute(name: attrName, foundationValue: attributeValue) } return nil } + /** + Returns the enumerated attributes in a specified range as an array of attribute-range pairs. + + - parameters: + - range: Contains the maximum range over which the attributes are enumerated. + - options: The options used by the enumeration. The values can be combined using C-bitwise OR. The values are described in `NSAttributedString.EnumerationOptions`. + - returns: An array of attribute-range tuples. Each tuples contains a range and the array of attributes that exist in that range. + */ + public func attributes(in range: Range, options: NSAttributedString.EnumerationOptions = []) -> [([Attribute], Range)] { + var attributeRanges = [([Attribute], Range)]() + enumerateAttributes(in: range, options: options) { attributes, range, _ in + attributeRanges.append((attributes, range)) + } + return attributeRanges + } + + /** + Executes the block for each attribute in the range. For discussion, see documentation for `NSAttributedString.enumerateAttributes(in:options:using:)`. + + - parameters: + + - enumerationRange: Contains the maximum range over which the attributes and values are enumerated, clipped to enumerationRange. + - options: The options used by the enumeration. The values can be combined using C-bitwise OR. The values are described in `NSAttributedString.EnumerationOptions`. + - block: The block to apply to ranges of the attribute in the attributed string. The block takes three arguments: + + + attrs: The attributes for the range. + + range: The run of the attributes. + + stop: A reference to a Boolean value. The block can set the value to `true` to stop further processing of the set. + The stop argument is an out-only argument. You should only ever set this Boolean to `true` within the block. + */ + public func enumerateAttributes(in enumerationRange: Range, options: NSAttributedString.EnumerationOptions = [], using block: (_ attrs: [Attribute], _ range: Range, _ stop: UnsafeMutablePointer) -> Void) { + enumerateAttributes(in: NSRange(enumerationRange), options: options) { attributes, range, ptr in + block(attributes.swiftyAttributes, range.location ..< (range.location + range.length), ptr) + } + } + + /** + Executes the block for the specified attribute run in the specified range. For discussion, see documentation for `NSAttributedString.enumerateAttribute(_:in:options:using:)`. + + - parameters: + + - attrName: The name of an attribute. + - enumerationRange: Contains the maximum range over which the attributes and values are enumerated, clipped to enumerationRange. + - options: The options used by the enumeration. The values can be combined using C-bitwise OR. The values are described in `NSAttributedString.EnumerationOptions`. + - block: The block to apply to ranges of the attribute in the attributed string. The block takes three arguments: + + + value: The value of the attribute. + + range: A range containing the run of the attribute. + + stop: A reference to a Boolean value. The block can set the value to `true` to stop further processing of the set. + The stop argument is an out-only argument. You should only ever set this Boolean to `true` within the block. + */ + public func enumerateAttribute(_ attrName: Attribute.Name, in enumerationRange: Range, options: NSAttributedString.EnumerationOptions = [], using block: (_ value: Any?, _ range: Range, _ stop: UnsafeMutablePointer) -> Void) { + enumerateAttribute(attrName.rawValue, in: NSRange(enumerationRange), options: options) { value, range, ptr in + block(value, range.location ..< (range.location + range.length), ptr) + } + } + } extension NSAttributedString { @@ -99,7 +148,7 @@ extension NSAttributedString { - parameter font: The font to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withFont(_ font: UIFont) -> NSMutableAttributedString { + public func withFont(_ font: Font) -> NSMutableAttributedString { return withAttribute(.font(font)) } @@ -109,7 +158,7 @@ extension NSAttributedString { - parameter style: The font to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withParagraphStyle(_ style: NSParagraphStyle) -> NSMutableAttributedString { + public func withParagraphStyle(_ style: ParagraphStyle) -> NSMutableAttributedString { return withAttribute(.paragraphStyle(style)) } @@ -119,7 +168,7 @@ extension NSAttributedString { - parameter color: The text color to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withTextColor(_ color: UIColor) -> NSMutableAttributedString { + public func withTextColor(_ color: Color) -> NSMutableAttributedString { return withAttribute(.textColor(color)) } @@ -129,7 +178,7 @@ extension NSAttributedString { - parameter color: The background color to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withBackgroundColor(_ color: UIColor) -> NSMutableAttributedString { + public func withBackgroundColor(_ color: Color) -> NSMutableAttributedString { return withAttribute(.backgroundColor(color)) } @@ -159,7 +208,7 @@ extension NSAttributedString { - parameter style: The strikethrough style to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withStrikethroughStyle(_ style: NSUnderlineStyle) -> NSMutableAttributedString { + public func withStrikethroughStyle(_ style: UnderlineStyle) -> NSMutableAttributedString { return withAttribute(.strikethroughStyle(style)) } @@ -169,7 +218,7 @@ extension NSAttributedString { - parameter style: The underline style to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withUnderlineStyle(_ style: NSUnderlineStyle) -> NSMutableAttributedString { + public func withUnderlineStyle(_ style: UnderlineStyle) -> NSMutableAttributedString { return withAttribute(.underlineStyle(style)) } @@ -179,7 +228,7 @@ extension NSAttributedString { - parameter color: The stroke color to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withStrokeColor(_ color: UIColor) -> NSMutableAttributedString { + public func withStrokeColor(_ color: Color) -> NSMutableAttributedString { return withAttribute(.strokeColor(color)) } @@ -193,15 +242,18 @@ extension NSAttributedString { return withAttribute(.strokeWidth(width)) } + #if os(watchOS) + #else /** Creates an attributed string with a specific shadow. - parameter shadow: The shadow to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withShadow(_ shadow: NSShadow) -> NSMutableAttributedString { + public func withShadow(_ shadow: Shadow) -> NSMutableAttributedString { return withAttribute(.shadow(shadow)) } + #endif /** Creates an attributed string with a specific text effect. @@ -213,15 +265,18 @@ extension NSAttributedString { return withAttribute(.textEffect(effect)) } + #if os(watchOS) + #else /** Creates an attributed string with a specific attachment. - parameter attachment: The attachment to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withAttachment(_ attachment: NSTextAttachment) -> NSMutableAttributedString { + public func withAttachment(_ attachment: TextAttachment) -> NSMutableAttributedString { return withAttribute(.attachment(attachment)) } + #endif /** Creates an attributed string with a specific link. @@ -249,7 +304,7 @@ extension NSAttributedString { - parameter color: The underline color to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withUnderlineColor(_ color: UIColor) -> NSMutableAttributedString { + public func withUnderlineColor(_ color: Color) -> NSMutableAttributedString { return withAttribute(.underlineColor(color)) } @@ -259,7 +314,7 @@ extension NSAttributedString { - parameter color: The underline style to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withStrikethroughColor(_ color: UIColor) -> NSMutableAttributedString { + public func withStrikethroughColor(_ color: Color) -> NSMutableAttributedString { return withAttribute(.strikethroughColor(color)) } @@ -283,6 +338,16 @@ extension NSAttributedString { return withAttribute(.expansion(expansion)) } + /** + Creates an attributed string with a specific vertical glyph form (horizontal or vertical writing direction). + + - parameter form: The horizontal/vertical writing direction to set for the attributed string. See `VerticalGlyphForm` for details. + - returns: A new attributed string with the newly added attribute. + */ + public func withVerticalGlyphForm(_ form: VerticalGlyphForm) -> NSMutableAttributedString { + return withAttribute(.verticalGlyphForm(form)) + } + /** Creates an attributed string with a specific writing direction. diff --git a/SwiftyAttributes/NSMutableAttributedString+SwiftyAttributes.swift b/SwiftyAttributes/Sources/common/NSMutableAttributedString+SwiftyAttributes.swift similarity index 100% rename from SwiftyAttributes/NSMutableAttributedString+SwiftyAttributes.swift rename to SwiftyAttributes/Sources/common/NSMutableAttributedString+SwiftyAttributes.swift diff --git a/SwiftyAttributes/Operators.swift b/SwiftyAttributes/Sources/common/Operators.swift similarity index 100% rename from SwiftyAttributes/Operators.swift rename to SwiftyAttributes/Sources/common/Operators.swift diff --git a/SwiftyAttributes/String+SwiftyAttributes.swift b/SwiftyAttributes/Sources/common/String+SwiftyAttributes.swift similarity index 72% rename from SwiftyAttributes/String+SwiftyAttributes.swift rename to SwiftyAttributes/Sources/common/String+SwiftyAttributes.swift index 907d30d..cf31837 100644 --- a/SwiftyAttributes/String+SwiftyAttributes.swift +++ b/SwiftyAttributes/Sources/common/String+SwiftyAttributes.swift @@ -30,22 +30,23 @@ extension String { return attributedString.withAttribute(attribute) } + /// Creates a mutable attributed string with the given string. + public var attributedString: NSMutableAttributedString { + return NSMutableAttributedString(string: self) + } + } extension String { - fileprivate var attributedString: NSAttributedString { - return NSAttributedString(string: self) - } - /** Creates an attributed string with a specific font. - parameter font: The font to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withFont(_ font: UIFont) -> NSMutableAttributedString { - return attributedString.withFont(font) + public func withFont(_ font: Font) -> NSMutableAttributedString { + return withAttribute(.font(font)) } /** @@ -54,8 +55,8 @@ extension String { - parameter style: The font to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withParagraphStyle(_ style: NSParagraphStyle) -> NSMutableAttributedString { - return attributedString.withParagraphStyle(style) + public func withParagraphStyle(_ style: ParagraphStyle) -> NSMutableAttributedString { + return withAttribute(.paragraphStyle(style)) } /** @@ -64,8 +65,8 @@ extension String { - parameter color: The text color to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withTextColor(_ color: UIColor) -> NSMutableAttributedString { - return attributedString.withTextColor(color) + public func withTextColor(_ color: Color) -> NSMutableAttributedString { + return withAttribute(.textColor(color)) } /** @@ -74,8 +75,8 @@ extension String { - parameter color: The background color to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withBackgroundColor(_ color: UIColor) -> NSMutableAttributedString { - return attributedString.withBackgroundColor(color) + public func withBackgroundColor(_ color: Color) -> NSMutableAttributedString { + return withAttribute(.backgroundColor(color)) } /** @@ -85,7 +86,7 @@ extension String { - returns: A new attributed string with the newly added attribute. */ public func withLigatures(_ ligatures: Ligatures) -> NSMutableAttributedString { - return attributedString.withLigatures(ligatures) + return withAttribute(.ligatures(ligatures)) } /** @@ -95,7 +96,7 @@ extension String { - returns: A new attributed string with the newly added attribute. */ public func withKern(_ kernValue: Double) -> NSMutableAttributedString { - return attributedString.withKern(kernValue) + return withAttribute(.kern(kernValue)) } /** @@ -104,8 +105,8 @@ extension String { - parameter style: The strikethrough style to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withStrikethroughStyle(_ style: NSUnderlineStyle) -> NSMutableAttributedString { - return attributedString.withStrikethroughStyle(style) + public func withStrikethroughStyle(_ style: StrikethroughStyle) -> NSMutableAttributedString { + return withAttribute(.strikethroughStyle(style)) } /** @@ -114,8 +115,8 @@ extension String { - parameter style: The underline style to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withUnderlineStyle(_ style: NSUnderlineStyle) -> NSMutableAttributedString { - return attributedString.withUnderlineStyle(style) + public func withUnderlineStyle(_ style: UnderlineStyle) -> NSMutableAttributedString { + return withAttribute(.underlineStyle(style)) } /** @@ -124,8 +125,8 @@ extension String { - parameter color: The stroke color to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withStrokeColor(_ color: UIColor) -> NSMutableAttributedString { - return attributedString.withStrokeColor(color) + public func withStrokeColor(_ color: Color) -> NSMutableAttributedString { + return withAttribute(.strokeColor(color)) } /** @@ -135,17 +136,7 @@ extension String { - returns: A new attributed string with the newly added attribute. */ public func withStrokeWidth(_ width: Double) -> NSMutableAttributedString { - return attributedString.withStrokeWidth(width) - } - - /** - Creates an attributed string with a specific shadow. - - - parameter shadow: The shadow to set for the attributed string. - - returns: A new attributed string with the newly added attribute. - */ - public func withShadow(_ shadow: NSShadow) -> NSMutableAttributedString { - return attributedString.withShadow(shadow) + return withAttribute(.strokeWidth(width)) } /** @@ -155,17 +146,7 @@ extension String { - returns: A new attributed string with the newly added attribute. */ public func withTextEffect(_ effect: TextEffect) -> NSMutableAttributedString { - return attributedString.withTextEffect(effect) - } - - /** - Creates an attributed string with a specific attachment. - - - parameter attachment: The attachment to set for the attributed string. - - returns: A new attributed string with the newly added attribute. - */ - public func withAttachment(_ attachment: NSTextAttachment) -> NSMutableAttributedString { - return attributedString.withAttachment(attachment) + return withAttribute(.textEffect(effect)) } /** @@ -175,7 +156,7 @@ extension String { - returns: A new attributed string with the newly added attribute. */ public func withLink(_ link: URL) -> NSMutableAttributedString { - return attributedString.withLink(link) + return withAttribute(.link(link)) } /** @@ -185,7 +166,7 @@ extension String { - returns: A new attributed string with the newly added attribute. */ public func withBaselineOffset(_ offset: Double) -> NSMutableAttributedString { - return attributedString.withBaselineOffset(offset) + return withAttribute(.baselineOffset(offset)) } /** @@ -194,8 +175,8 @@ extension String { - parameter color: The underline color to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withUnderlineColor(_ color: UIColor) -> NSMutableAttributedString { - return attributedString.withUnderlineColor(color) + public func withUnderlineColor(_ color: Color) -> NSMutableAttributedString { + return withAttribute(.underlineColor(color)) } /** @@ -204,8 +185,8 @@ extension String { - parameter color: The underline style to set for the attributed string. - returns: A new attributed string with the newly added attribute. */ - public func withStrikethroughColor(_ color: UIColor) -> NSMutableAttributedString { - return attributedString.withStrikethroughColor(color) + public func withStrikethroughColor(_ color: Color) -> NSMutableAttributedString { + return withAttribute(.strikethroughColor(color)) } /** @@ -215,7 +196,7 @@ extension String { - returns: A new attributed string with the newly added attribute. */ public func withObliqueness(_ obliquenessValue: Double) -> NSMutableAttributedString { - return attributedString.withObliqueness(obliquenessValue) + return withAttribute(.obliqueness(obliquenessValue)) } /** @@ -225,7 +206,7 @@ extension String { - returns: A new attributed string with the newly added attribute. */ public func withExpansion(_ expansion: Double) -> NSMutableAttributedString { - return attributedString.withExpansion(expansion) + return withAttribute(.expansion(expansion)) } /** @@ -235,7 +216,42 @@ extension String { - returns: A new attributed string with the newly added attribute. */ public func withWritingDirections(_ directions: [WritingDirection]) -> NSMutableAttributedString { - return attributedString.withWritingDirections(directions) + return withAttribute(.writingDirections(directions)) + } + + /** + Creates an attributed string with a specific vertical glyph form (horizontal or vertical writing direction). + + - parameter form: The horizontal/vertical writing direction to set for the attributed string. See `VerticalGlyphForm` for details. + - returns: A new attributed string with the newly added attribute. + */ + public func withVerticalGlyphForm(_ form: VerticalGlyphForm) -> NSMutableAttributedString { + return withAttribute(.verticalGlyphForm(form)) + } + + #if os(watchOS) + #else + + /** + Creates an attributed string with a specific shadow. + + - parameter shadow: The shadow to set for the attributed string. + - returns: A new attributed string with the newly added attribute. + */ + public func withShadow(_ shadow: Shadow) -> NSMutableAttributedString { + return withAttribute(.shadow(shadow)) } + /** + Creates an attributed string with a specific attachment. + + - parameter attachment: The attachment to set for the attributed string. + - returns: A new attributed string with the newly added attribute. + */ + public func withAttachment(_ attachment: TextAttachment) -> NSMutableAttributedString { + return withAttribute(.attachment(attachment)) + } + + #endif + } diff --git a/SwiftyAttributes/TextEffect.swift b/SwiftyAttributes/Sources/common/TextEffect.swift similarity index 92% rename from SwiftyAttributes/TextEffect.swift rename to SwiftyAttributes/Sources/common/TextEffect.swift index b9a51e6..f6562ca 100644 --- a/SwiftyAttributes/TextEffect.swift +++ b/SwiftyAttributes/Sources/common/TextEffect.swift @@ -6,7 +6,11 @@ // Copyright © 2016 Eddie Kaiger. All rights reserved. // -import Foundation +#if os(macOS) + import AppKit +#else + import UIKit +#endif /** An enum describing the possible values for text effects on attributed strings. diff --git a/SwiftyAttributes/Sources/common/VerticalGlyphForm.swift b/SwiftyAttributes/Sources/common/VerticalGlyphForm.swift new file mode 100644 index 0000000..f501f3c --- /dev/null +++ b/SwiftyAttributes/Sources/common/VerticalGlyphForm.swift @@ -0,0 +1,23 @@ +// +// VerticalGlyphForm.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 11/16/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +import Foundation + +/** + An enum to indicate horizontal or vertical writing direction. On iOS, only horizontal form is valid. + */ +public enum VerticalGlyphForm: Int { + + /// Horizontal writing direction. + case horizontal = 0 + + #if os(macOS) + /// Vertical writing direction. + case vertical = 1 + #endif +} diff --git a/SwiftyAttributes/WritingDirection.swift b/SwiftyAttributes/Sources/common/WritingDirection.swift similarity index 91% rename from SwiftyAttributes/WritingDirection.swift rename to SwiftyAttributes/Sources/common/WritingDirection.swift index e47ad11..8368664 100644 --- a/SwiftyAttributes/WritingDirection.swift +++ b/SwiftyAttributes/Sources/common/WritingDirection.swift @@ -6,9 +6,13 @@ // Copyright © 2016 Eddie Kaiger. All rights reserved. // -import UIKit +#if os(macOS) + import AppKit +#else + import UIKit +#endif -@available(iOS 9.0, *) +@available(iOS 9.0, OSX 10.11, *) private func mappingValue(direction: NSWritingDirection, formatType: NSWritingDirectionFormatType) -> Int { return direction.rawValue | formatType.rawValue } @@ -31,7 +35,7 @@ public enum WritingDirection: RawRepresentable { case rightToLeftEmbedding public init?(rawValue: Int) { - guard #available(iOS 9.0, *) else { return nil } + guard #available(iOS 9.0, macOS 10.11, *) else { return nil } switch rawValue { case mappingValue(direction: .leftToRight, formatType: .override): self = .leftToRightOverride case mappingValue(direction: .rightToLeft, formatType: .override): self = .rightToLeftOverride @@ -42,7 +46,7 @@ public enum WritingDirection: RawRepresentable { } public var rawValue: Int { - guard #available(iOS 9.0, *) else { return 0 } + guard #available(iOS 9.0, macOS 10.11, *) else { return 0 } switch self { case .leftToRightOverride: return mappingValue(direction: .leftToRight, formatType: .override) case .rightToLeftOverride: return mappingValue(direction: .rightToLeft, formatType: .override) diff --git a/SwiftyAttributes/Sources/macOS/NSAttributedString+macOS.swift b/SwiftyAttributes/Sources/macOS/NSAttributedString+macOS.swift new file mode 100644 index 0000000..b98ff0e --- /dev/null +++ b/SwiftyAttributes/Sources/macOS/NSAttributedString+macOS.swift @@ -0,0 +1,93 @@ +// +// NSAttributedString+macOS.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 11/17/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +#if os(macOS) +import AppKit + +extension NSAttributedString { + + /** + Creates an attributed string with a cursor object. + + - parameter cursor: The cursor to set for the attributed string. + - returns: A new attributed string with the newly added attribute. + */ + public func withCursor(_ cursor: Cursor) -> NSMutableAttributedString { + return withAttribute(.cursor(cursor)) + } + + /** + Creates an attributed string with the specified marked clause segment. + + - parameter markedClauseSegment: The index in marked text indicating clause segments. + - returns: A new attributed string with the newly added attribute. + */ + public func withMarkedClauseSegment(_ segment: Int) -> NSMutableAttributedString { + return withAttribute(.markedClauseSegment(segment)) + } + + /** + Creates an attributed string with the specified spelling state. + + - parameter state: A state indicating a spelling or grammar error. See `SpellingState` for possible values. + - returns: A new attributed string with the newly added attribute. + */ + public func withSpellingState(_ state: SpellingState) -> NSMutableAttributedString { + return withAttribute(.spellingState(state)) + } + + /** + Creates an attributed string with the specified superscript value. + + - parameter superscript: The superscript to set for the attributed string. + - returns: A new attributed string with the newly added attribute. + */ + public func withSuperscript(_ superscript: Int) -> NSMutableAttributedString { + return withAttribute(.superscript(superscript)) + } + + /** + Creates an attributed string with the specified text alternatives object. + + - parameter textAlternatives: The NSTextAlternatives object representing alternatives for a string that may be presented to the user. + - returns: A new attributed string with the newly added attribute. + */ + public func withTextAlternatives(_ textAlternatives: TextAlternatives) -> NSMutableAttributedString { + return withAttribute(.textAlternatives(textAlternatives)) + } + + /** + Creates an attributed string with a tooltip message. + + - parameter toolTip: The toolTip message to set for the attributed string. + - returns: A new attributed string with the newly added attribute. + */ + public func withToolTip(_ toolTip: String) -> NSMutableAttributedString { + return withAttribute(.toolTip(toolTip)) + } + +} + +extension NSAttributedString { + + /** + Returns the font attributes in effect for the character at the given location. + */ + public func fontAttributes(in range: Range) -> [Attribute] { + return fontAttributes(in: NSRange(range)).swiftyAttributes + } + + /** + Returns the ruler (paragraph) attributes in effect for the characters within the given range. + */ + public func rulerAttributes(in range: Range) -> [Attribute] { + return rulerAttributes(in: NSRange(range)).swiftyAttributes + } + +} +#endif diff --git a/SwiftyAttributes/Sources/macOS/SpellingState.swift b/SwiftyAttributes/Sources/macOS/SpellingState.swift new file mode 100644 index 0000000..ccab115 --- /dev/null +++ b/SwiftyAttributes/Sources/macOS/SpellingState.swift @@ -0,0 +1,45 @@ +// +// SpellingState.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 11/16/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +#if os(macOS) +import AppKit + +/** + This enum controls the display of the spelling and grammar indicators on text, + highlighting portions of the text that are flagged for spelling or grammar issues. + This should be used with `Attribute.spellingState`. + */ +public enum SpellingState: RawRepresentable { + + /// No spelling or grammar indicator. + case none + + /// The spelling error indicator. + case spellingFlag + + /// The grammar error indicator. + case grammarFlag + + public init?(rawValue: Int) { + switch rawValue { + case 0: self = .none + case NSSpellingStateSpellingFlag: self = .spellingFlag + case NSSpellingStateGrammarFlag: self = .grammarFlag + default: return nil + } + } + + public var rawValue: Int { + switch self { + case .none: return 0 + case .spellingFlag: return NSSpellingStateSpellingFlag + case .grammarFlag: return NSSpellingStateGrammarFlag + } + } +} +#endif diff --git a/SwiftyAttributes/Sources/macOS/String+macOS.swift b/SwiftyAttributes/Sources/macOS/String+macOS.swift new file mode 100644 index 0000000..b9cfa63 --- /dev/null +++ b/SwiftyAttributes/Sources/macOS/String+macOS.swift @@ -0,0 +1,77 @@ +// +// String+macOS.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 11/29/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + + +#if os(macOS) +import AppKit + +extension String { + + /** + Creates an attributed string with a cursor object. + + - parameter cursor: The cursor to set for the attributed string. + - returns: A new attributed string with the newly added attribute. + */ + public func withCursor(_ cursor: Cursor) -> NSMutableAttributedString { + return withAttribute(.cursor(cursor)) + } + + /** + Creates an attributed string with the specified marked clause segment. + + - parameter markedClauseSegment: The index in marked text indicating clause segments. + - returns: A new attributed string with the newly added attribute. + */ + public func withMarkedClauseSegment(_ segment: Int) -> NSMutableAttributedString { + return withAttribute(.markedClauseSegment(segment)) + } + + /** + Creates an attributed string with the specified spelling state. + + - parameter state: A state indicating a spelling or grammar error. See `SpellingState` for possible values. + - returns: A new attributed string with the newly added attribute. + */ + public func withSpellingState(_ state: SpellingState) -> NSMutableAttributedString { + return withAttribute(.spellingState(state)) + } + + /** + Creates an attributed string with the specified superscript value. + + - parameter superscript: The superscript to set for the attributed string. + - returns: A new attributed string with the newly added attribute. + */ + public func withSuperscript(_ superscript: Int) -> NSMutableAttributedString { + return withAttribute(.superscript(superscript)) + } + + /** + Creates an attributed string with the specified text alternatives object. + + - parameter textAlternatives: The NSTextAlternatives object representing alternatives for a string that may be presented to the user. + - returns: A new attributed string with the newly added attribute. + */ + public func withTextAlternatives(_ textAlternatives: TextAlternatives) -> NSMutableAttributedString { + return withAttribute(.textAlternatives(textAlternatives)) + } + + /** + Creates an attributed string with a tooltip message. + + - parameter toolTip: The toolTip message to set for the attributed string. + - returns: A new attributed string with the newly added attribute. + */ + public func withToolTip(_ toolTip: String) -> NSMutableAttributedString { + return withAttribute(.toolTip(toolTip)) + } + +} + +#endif diff --git a/SwiftyAttributes/SwiftyAttributes.h b/SwiftyAttributes/SwiftyAttributes.h index 0be1806..6ef1eb6 100644 --- a/SwiftyAttributes/SwiftyAttributes.h +++ b/SwiftyAttributes/SwiftyAttributes.h @@ -2,18 +2,11 @@ // SwiftyAttributes.h // SwiftyAttributes // -// Created by Eddie Kaiger on 9/30/16. +// Created by Eddie Kaiger on 11/9/16. // Copyright © 2016 Eddie Kaiger. All rights reserved. // -#import +#import -//! Project version number for SwiftyAttributes. FOUNDATION_EXPORT double SwiftyAttributesVersionNumber; - -//! Project version string for SwiftyAttributes. FOUNDATION_EXPORT const unsigned char SwiftyAttributesVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/SwiftyAttributesTests/Attribute+Sequence_Tests.swift b/SwiftyAttributesTests/Attribute+Sequence_Tests.swift new file mode 100644 index 0000000..dc2efa5 --- /dev/null +++ b/SwiftyAttributesTests/Attribute+Sequence_Tests.swift @@ -0,0 +1,55 @@ +// +// Attribute+Sequence_Tests.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 11/26/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +import XCTest +import SwiftyAttributes + +class Attribute_Sequence_Tests: XCTestCase { + + func testDictionaryToSwiftyAttributes() { + let dict: [String: Any] = [ + NSBaselineOffsetAttributeName: 3.2, + NSExpansionAttributeName: 5, + NSUnderlineStyleAttributeName: NSUnderlineStyle.styleDouble.rawValue + ] + let sort: (Attribute, Attribute) -> Bool = { $0.0.keyName < $0.1.keyName } + let expected: [Attribute] = [ + .baselineOffset(3.2), + .expansion(5), + .underlineStyle(.styleDouble) + ].sorted(by: sort) + XCTAssertEqual(dict.swiftyAttributes.sorted(by: sort), expected) + } + + func testDictionaryToSwiftyAttributes_withInvalidValues() { + let dict: [String: Any] = [ + NSBaselineOffsetAttributeName: 3.2, + NSUnderlineStyleAttributeName: NSUnderlineStyle.styleDouble.rawValue, + "Sah dude": 5 + ] + let sort: (Attribute, Attribute) -> Bool = { $0.0.keyName < $0.1.keyName } + let expected: [Attribute] = [ + .baselineOffset(3.2), + .underlineStyle(.styleDouble) + ].sorted(by: sort) + XCTAssertEqual(dict.swiftyAttributes.sorted(by: sort), expected) + } + + func testAttributesArrayToFoundationDictionary() { + let attrs: [Attribute] = [ + .kern(3.5), + .link(URL(string: "www.google.com")!) + ] + let expected: [String: Any] = [ + NSKernAttributeName: 3.5, + NSLinkAttributeName: URL(string: "www.google.com")! + ] + XCTAssertEqual(expected as NSDictionary, attrs.foundationAttributes as NSDictionary) + } + +} diff --git a/SwiftyAttributesTests/Attribute_Tests.swift b/SwiftyAttributesTests/Attribute_Tests.swift index dfa7a55..3582456 100644 --- a/SwiftyAttributesTests/Attribute_Tests.swift +++ b/SwiftyAttributesTests/Attribute_Tests.swift @@ -32,6 +32,15 @@ class Attribute_Tests: XCTestCase { XCTAssertEqual(Attribute.Name(rawValue: NSUnderlineColorAttributeName)!, .underlineColor) XCTAssertEqual(Attribute.Name(rawValue: NSUnderlineStyleAttributeName)!, .underlineStyle) XCTAssertEqual(Attribute.Name(rawValue: NSWritingDirectionAttributeName)!, .writingDirection) + XCTAssertEqual(Attribute.Name(rawValue: NSVerticalGlyphFormAttributeName)!, .verticalGlyphForm) + #if os(macOS) + XCTAssertEqual(Attribute.Name(rawValue: NSCursorAttributeName), .cursor) + XCTAssertEqual(Attribute.Name(rawValue: NSMarkedClauseSegmentAttributeName), .markedClauseSegment) + XCTAssertEqual(Attribute.Name(rawValue: NSSpellingStateAttributeName), .spellingState) + XCTAssertEqual(Attribute.Name(rawValue: NSSuperscriptAttributeName), .superscript) + XCTAssertEqual(Attribute.Name(rawValue: NSTextAlternativesAttributeName), .textAlternatives) + XCTAssertEqual(Attribute.Name(rawValue: NSToolTipAttributeName), .toolTip) + #endif XCTAssertNil(Attribute.Name(rawValue: "SomeAttribute")) } diff --git a/SwiftyAttributesTests/NSAttributedString_Tests.swift b/SwiftyAttributesTests/NSAttributedString_Tests.swift index 28030d4..d50d71b 100644 --- a/SwiftyAttributesTests/NSAttributedString_Tests.swift +++ b/SwiftyAttributesTests/NSAttributedString_Tests.swift @@ -13,7 +13,7 @@ class NSAttributedString_Tests: XCTestCase { func testInit_withStringAndAttributes() { let subject = NSAttributedString(string: "Hello World", attributes: [.strokeColor(.green), .strokeWidth(3)]) - let expected = NSAttributedString(string: "Hello World", attributes: [NSStrokeColorAttributeName: UIColor.green, NSStrokeWidthAttributeName: 3]) + let expected = NSAttributedString(string: "Hello World", attributes: [NSStrokeColorAttributeName: Color.green, NSStrokeWidthAttributeName: 3]) XCTAssertEqual(subject, expected) } @@ -28,11 +28,15 @@ class NSAttributedString_Tests: XCTestCase { // MARK: - Attribute At Location func testAttributeAtLocation_attachment() { - let attachment = NSTextAttachment() - attachment.image = UIImage(named: "Star", in: Bundle(for: type(of: self)), compatibleWith: nil)! + let attachment = TextAttachment() + #if os(macOS) + attachment.image = NSImage() + #else + attachment.image = UIImage(named: "Star", in: Bundle(for: type(of: self)), compatibleWith: nil)! + #endif let str = "Hello".withAttachment(attachment) - let subject = str.attribute(.attachment, at: 0, effectiveRange: nil)!.value as! NSTextAttachment - let expected = str.attribute(NSAttachmentAttributeName, at: 0, effectiveRange: nil) as! NSTextAttachment + let subject = str.attribute(.attachment, at: 0, effectiveRange: nil)!.value as! TextAttachment + let expected = str.attribute(NSAttachmentAttributeName, at: 0, effectiveRange: nil) as! TextAttachment XCTAssertEqual(subject, expected) XCTAssertEqual(subject, attachment) } @@ -47,24 +51,24 @@ class NSAttributedString_Tests: XCTestCase { func testAttributeAtLocation_backgroundColor() { let str = "Hello".withBackgroundColor(.blue) - let subject = str.attribute(.backgroundColor, at: 0, effectiveRange: nil)!.value as! UIColor - let expected = str.attribute(NSBackgroundColorAttributeName, at: 0, effectiveRange: nil) as! UIColor + let subject = str.attribute(.backgroundColor, at: 0, effectiveRange: nil)!.value as! Color + let expected = str.attribute(NSBackgroundColorAttributeName, at: 0, effectiveRange: nil) as! Color XCTAssertEqual(subject, expected) XCTAssertEqual(subject, .blue) } func testAttributeAtLocation_expansion() { - let str = "Hello".withExpansion(5.1) + let str = "Hello".withExpansion(5) let subject = str.attribute(.expansion, at: 0, effectiveRange: nil)!.value as! Double let expected = str.attribute(NSExpansionAttributeName, at: 0, effectiveRange: nil) as! Double XCTAssertEqual(subject, expected) - XCTAssertEqual(subject, 5.1) + XCTAssertEqual(subject, 5) } func testAttributeAtLocation_font() { let str = "Hello".withFont(.systemFont(ofSize: 26)) - let subject = str.attribute(.font, at: 0, effectiveRange: nil)!.value as! UIFont - let expected = str.attribute(NSFontAttributeName, at: 0, effectiveRange: nil) as! UIFont + let subject = str.attribute(.font, at: 0, effectiveRange: nil)!.value as! Font + let expected = str.attribute(NSFontAttributeName, at: 0, effectiveRange: nil) as! Font XCTAssertEqual(subject, expected) XCTAssertEqual(subject, .systemFont(ofSize: 26)) } @@ -107,26 +111,26 @@ class NSAttributedString_Tests: XCTestCase { style.lineSpacing = 3.4 style.alignment = .right let str = "Hello".withParagraphStyle(style) - let subject = str.attribute(.paragraphStyle, at: 0, effectiveRange: nil)!.value as! NSParagraphStyle - let expected = str.attribute(NSParagraphStyleAttributeName, at: 0, effectiveRange: nil) as! NSParagraphStyle + let subject = str.attribute(.paragraphStyle, at: 0, effectiveRange: nil)!.value as! ParagraphStyle + let expected = str.attribute(NSParagraphStyleAttributeName, at: 0, effectiveRange: nil) as! ParagraphStyle XCTAssertEqual(subject, expected) XCTAssertEqual(subject, style) } func testAttributeAtLocation_shadow() { - let shadow = NSShadow() + let shadow = Shadow() shadow.shadowOffset = CGSize(width: 3, height: 5) let str = "Hello".withShadow(shadow) - let subject = str.attribute(.shadow, at: 0, effectiveRange: nil)!.value as! NSShadow - let expected = str.attribute(NSShadowAttributeName, at: 0, effectiveRange: nil) as! NSShadow + let subject = str.attribute(.shadow, at: 0, effectiveRange: nil)!.value as! Shadow + let expected = str.attribute(NSShadowAttributeName, at: 0, effectiveRange: nil) as! Shadow XCTAssertEqual(subject, expected) XCTAssertEqual(subject, shadow) } func testAttributeAtLocation_strokeColor() { let str = "Hello".withStrokeColor(.magenta) - let subject = str.attribute(.strokeColor, at: 0, effectiveRange: nil)!.value as! UIColor - let expected = str.attribute(NSStrokeColorAttributeName, at: 0, effectiveRange: nil) as! UIColor + let subject = str.attribute(.strokeColor, at: 0, effectiveRange: nil)!.value as! Color + let expected = str.attribute(NSStrokeColorAttributeName, at: 0, effectiveRange: nil) as! Color XCTAssertEqual(subject, expected) XCTAssertEqual(subject, .magenta) } @@ -141,8 +145,8 @@ class NSAttributedString_Tests: XCTestCase { func testAttributeAtLocation_strikethroughColor() { let str = "Hello".withStrikethroughColor(.orange) - let subject = str.attribute(.strikethroughColor, at: 0, effectiveRange: nil)!.value as! UIColor - let expected = str.attribute(NSStrikethroughColorAttributeName, at: 0, effectiveRange: nil) as! UIColor + let subject = str.attribute(.strikethroughColor, at: 0, effectiveRange: nil)!.value as! Color + let expected = str.attribute(NSStrikethroughColorAttributeName, at: 0, effectiveRange: nil) as! Color XCTAssertEqual(subject, expected) XCTAssertEqual(subject, .orange) } @@ -157,8 +161,8 @@ class NSAttributedString_Tests: XCTestCase { func testAttributeAtLocation_textColor() { let str = "Hello".withTextColor(.green) - let subject = str.attribute(.textColor, at: 0, effectiveRange: nil)!.value as! UIColor - let expected = str.attribute(NSForegroundColorAttributeName, at: 0, effectiveRange: nil) as! UIColor + let subject = str.attribute(.textColor, at: 0, effectiveRange: nil)!.value as! Color + let expected = str.attribute(NSForegroundColorAttributeName, at: 0, effectiveRange: nil) as! Color XCTAssertEqual(subject, expected) XCTAssertEqual(subject, .green) } @@ -173,20 +177,28 @@ class NSAttributedString_Tests: XCTestCase { func testAttributeAtLocation_underlineColor() { let str = "Hello".withUnderlineColor(.blue) - let subject = str.attribute(.underlineColor, at: 0, effectiveRange: nil)!.value as! UIColor - let expected = str.attribute(NSUnderlineColorAttributeName, at: 0, effectiveRange: nil) as! UIColor + let subject = str.attribute(.underlineColor, at: 0, effectiveRange: nil)!.value as! Color + let expected = str.attribute(NSUnderlineColorAttributeName, at: 0, effectiveRange: nil) as! Color XCTAssertEqual(subject, expected) XCTAssertEqual(subject, .blue) } func testAttributeAtLocation_underlineStyle() { let str = "Hello".withUnderlineStyle(.byWord) - let subject = str.attribute(.underlineStyle, at: 0, effectiveRange: nil)!.value as! NSUnderlineStyle + let subject = str.attribute(.underlineStyle, at: 0, effectiveRange: nil)!.value as! UnderlineStyle let expected = str.attribute(NSUnderlineStyleAttributeName, at: 0, effectiveRange: nil) as! Int XCTAssertEqual(subject.rawValue, expected) XCTAssertEqual(subject, .byWord) } + func testAttributeAtLocation_verticalGlyphForm() { + let str = "Hello".withVerticalGlyphForm(.horizontal) + let subject = str.attribute(.verticalGlyphForm, at: 0, effectiveRange: nil)!.value as! VerticalGlyphForm + let expected = str.attribute(NSVerticalGlyphFormAttributeName, at: 0, effectiveRange: nil) as! Int + XCTAssertEqual(subject.rawValue, expected) + XCTAssertEqual(subject, .horizontal) + } + func testAttributeAtLocation_writingDirections() { let str = "Hello".withWritingDirections([.leftToRightOverride, .rightToLeftEmbedding]) let subject = str.attribute(.writingDirection, at: 0, effectiveRange: nil)!.value as! [WritingDirection] @@ -207,7 +219,7 @@ class NSAttributedString_Tests: XCTestCase { let str = "Hello".withUnderlineStyle(.patternDot) + "World".withUnderlineColor(.magenta) var swiftyRange = NSRange() var foundationRange = NSRange() - let subject = str.attribute(.underlineStyle, at: 0, effectiveRange: &swiftyRange)!.value as! NSUnderlineStyle + let subject = str.attribute(.underlineStyle, at: 0, effectiveRange: &swiftyRange)!.value as! UnderlineStyle let expected = str.attribute(NSUnderlineStyleAttributeName, at: 0, effectiveRange: &foundationRange) as! Int XCTAssertEqual(subject.rawValue, expected) XCTAssertEqual(subject, .patternDot) @@ -231,4 +243,201 @@ class NSAttributedString_Tests: XCTestCase { XCTAssertEqual(swiftyRange.location, 5) } + #if os(macOS) + + func testAttributeAtLocation_cursor() { + let cursor = Cursor(image: NSImage(), foregroundColorHint: .blue, backgroundColorHint: .red, hotSpot: NSPoint(x: 2, y: 2)) + let str = "Hello".withCursor(cursor) + let subject = str.attribute(.cursor, at: 0, effectiveRange: nil)!.value as! Cursor + let expected = str.attribute(NSCursorAttributeName, at: 0, effectiveRange: nil) as! Cursor + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject, cursor) + } + + func testAttributeAtLocation_markedClauseSegment() { + let str = "Hello".withMarkedClauseSegment(2) + let subject = str.attribute(.markedClauseSegment, at: 0, effectiveRange: nil)!.value as! Int + let expected = str.attribute(NSMarkedClauseSegmentAttributeName, at: 0, effectiveRange: nil) as! Int + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject, 2) + } + + func testAttributeAtLocation_spellingState() { + let str = "Hello".withSpellingState(.grammarFlag) + let subject = str.attribute(.spellingState, at: 0, effectiveRange: nil)!.value as! SpellingState + let expected = str.attribute(NSSpellingStateAttributeName, at: 0, effectiveRange: nil) as! Int + XCTAssertEqual(subject.rawValue, expected) + XCTAssertEqual(subject, .grammarFlag) + } + + func testAttributeAtLocation_superscript() { + let str = "Hello".withSuperscript(3) + let subject = str.attribute(.superscript, at: 0, effectiveRange: nil)!.value as! Int + let expected = str.attribute(NSSuperscriptAttributeName, at: 0, effectiveRange: nil) as! Int + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject, 3) + } + + func testAttributeAtLocation_textAlternatives() { + let alternatives = TextAlternatives(primaryString: "Hi", alternativeStrings: ["Sup", "Yo"]) + let str = "Hello".withTextAlternatives(alternatives) + let subject = str.attribute(.textAlternatives, at: 0, effectiveRange: nil)!.value as! TextAlternatives + let expected = str.attribute(NSTextAlternativesAttributeName, at: 0, effectiveRange: nil) as! TextAlternatives + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject, alternatives) + } + + func testAttributeAtLocation_toolTip() { + let str = "Hello".withToolTip("Yo") + let subject = str.attribute(.toolTip, at: 0, effectiveRange: nil)!.value as! String + let expected = str.attribute(NSToolTipAttributeName, at: 0, effectiveRange: nil) as! String + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject, "Yo") + } + + // MARK: - Font Attributes + + func testFontAttributes_onlyFontAttributes() { + let subject = "Hello".withFont(.systemFont(ofSize: 19)).fontAttributes(in: 0 ..< 3).foundationAttributes + let expected = NSAttributedString(string: "Hello", attributes: [NSFontAttributeName: Font.systemFont(ofSize: 19)]).fontAttributes(in: NSRange(location: 0, length: 3)) + XCTAssertEqual(subject as NSDictionary, expected as NSDictionary) + XCTAssertEqual(subject.swiftyAttributes, [.font(.systemFont(ofSize: 19))]) + } + + func testFontAttributes_includesNonFontAttributes() { + let url = URL(string: "www.google.com")! + let subject = "Hello".withAttributes([.font(.systemFont(ofSize: 19)), .link(url)]).fontAttributes(in: 0 ..< 3).foundationAttributes + let expected = NSAttributedString(string: "Hello", attributes: [NSFontAttributeName: Font.systemFont(ofSize: 19), NSLinkAttributeName: url]).fontAttributes(in: NSRange(location: 0, length: 3)) + XCTAssertEqual(subject as NSDictionary, expected as NSDictionary) + XCTAssertEqual(subject.swiftyAttributes, [.font(.systemFont(ofSize: 19))]) + } + + // MARK: - Ruler Attributes + + func testRulerAttributes_onlyRulerAttributes() { + let style = NSMutableParagraphStyle() + style.alignment = .center + let subject = "Hello".withParagraphStyle(style).rulerAttributes(in: 1 ..< 3).foundationAttributes + let expected = NSAttributedString(string: "Hello", attributes: [NSParagraphStyleAttributeName: style]).rulerAttributes(in: NSRange(location: 1, length: 2)) + XCTAssertEqual(subject as NSDictionary, expected as NSDictionary) + XCTAssertEqual(subject.swiftyAttributes, [.paragraphStyle(style)]) + } + + func testRulerAttributes_includesNonRulerAttributes() { + let style = NSMutableParagraphStyle() + style.alignment = .center + let subject = "Hello".withAttributes([.paragraphStyle(style), .textColor(.cyan)]).rulerAttributes(in: 1 ..< 3).foundationAttributes + let expected = NSAttributedString(string: "Hello", attributes: [NSParagraphStyleAttributeName: style, NSForegroundColorAttributeName: Color.cyan]).rulerAttributes(in: NSRange(location: 1, length: 2)) + XCTAssertEqual(subject as NSDictionary, expected as NSDictionary) + XCTAssertEqual(subject.swiftyAttributes, [.paragraphStyle(style)]) + } + + #endif + + // MARK: Enumeration + + func testEnumerateSingleAttribute() { + let str = "Hello".withExpansion(3) + "World".attributedString + var enumerated = false + str.enumerateAttribute(.expansion, in: 0 ..< 7) { value, range, _ in + enumerated = true + if range.upperBound == 5 { + XCTAssertEqual(value as! Double, 3) + XCTAssertEqual(range, 0 ..< 5) + } else { + XCTAssertNil(value) + XCTAssertEqual(range, 5 ..< 7) + } + } + XCTAssertTrue(enumerated) + } + + func testEnumerateMultipleAttributes() { + var attrs: [Attribute] = [.backgroundColor(.red), .baselineOffset(2), .obliqueness(3)] + let str = "Hello World! How is everyone?".attributedString + str.addAttributes(attrs, range: 0 ..< 7) + attrs[2] = .obliqueness(2) + str.addAttributes(attrs, range: 7 ..< 12) + str.addAttributes(attrs + [.kern(4)], range: 12 ..< 17) + + let sort: (Attribute, Attribute) -> Bool = { $0.0.keyName < $0.1.keyName } + + var enumerated = false + str.enumerateAttributes(in: 3 ..< 15) { attrs, range, _ in + enumerated = true + + switch range.upperBound { + case 7: + XCTAssertEqual(attrs.sorted(by: sort), [.backgroundColor(.red), .baselineOffset(2), .obliqueness(3)]) + XCTAssertEqual(range, 3 ..< 7) + case 12: + XCTAssertEqual(attrs.sorted(by: sort), [.backgroundColor(.red), .baselineOffset(2), .obliqueness(2)]) + XCTAssertEqual(range, 7 ..< 12) + case 15: + XCTAssertEqual(attrs.sorted(by: sort), [.backgroundColor(.red), .baselineOffset(2), .kern(4), .obliqueness(2)]) + XCTAssertEqual(range, 12 ..< 15) + default: + XCTFail("Incorrect upper bound when enumerating attributes") + } + } + + XCTAssertTrue(enumerated) + } + + func testEnumerate_stopValue() { + let str = "Hello".withBackgroundColor(.blue) + "World".withKern(3) + "!".withTextColor(.magenta) + var enumerations = 0 + str.enumerateAttributes(in: 0 ..< str.length) { _ in + enumerations += 1 + } + XCTAssertEqual(enumerations, 3) + enumerations = 0 + str.enumerateAttributes(in: 0 ..< str.length) { _, _, stop in + enumerations += 1 + if enumerations == 2 { + stop.pointee = ObjCBool(true) + } + } + XCTAssertEqual(enumerations, 2) + } + + func testEnumerate_options() { + let str = "Hello".withExpansion(3) + "World".attributedString + var enumeratedEnding = false + str.enumerateAttribute(.expansion, in: 0 ..< 7, options: .reverse) { value, range, _ in + if range.upperBound == 7 { + enumeratedEnding = true + XCTAssertNil(value) + } else { + XCTAssertTrue(enumeratedEnding) + XCTAssertEqual(value as! Double, 3) + } + } + } + + func testEnumerate_returnsArrayOfTuples() { + var attrs: [Attribute] = [.backgroundColor(.red), .obliqueness(3)] + let str = "Hello World! How is everyone?".attributedString + str.addAttributes(attrs, range: 0 ..< 7) + attrs[1] = .obliqueness(2) + str.addAttributes(attrs, range: 7 ..< 12) + str.addAttributes(attrs + [.kern(4)], range: 12 ..< 17) + + let sort: (Attribute, Attribute) -> Bool = { $0.0.keyName < $0.1.keyName } + + let subject = str.attributes(in: 3 ..< 15) + let expected: [([Attribute], Range)] = [ + ([.backgroundColor(.red), .obliqueness(3)], 3 ..< 7), + ([.backgroundColor(.red), .obliqueness(2)], 7 ..< 12), + ([.backgroundColor(.red), .kern(4), .obliqueness(2)], 12 ..< 15) + ] + + XCTAssertEqual(subject.count, 3) + + for (index, tuple) in subject.enumerated() { + XCTAssertEqual(tuple.0.sorted(by: sort), expected[index].0.sorted(by: sort)) + XCTAssertEqual(tuple.1, expected[index].1) + } + } + } diff --git a/SwiftyAttributesTests/NSMutableAttributedString_Tests.swift b/SwiftyAttributesTests/NSMutableAttributedString_Tests.swift index cbbffaf..f91f877 100644 --- a/SwiftyAttributesTests/NSMutableAttributedString_Tests.swift +++ b/SwiftyAttributesTests/NSMutableAttributedString_Tests.swift @@ -27,7 +27,7 @@ class NSMutableAttributedString_Tests: XCTestCase { XCTAssertEqual(subject, expected) subject.addAttributes([.font(.boldSystemFont(ofSize: 17))], range: NSRange(location: 0, length: 1)) XCTAssertNotEqual(subject, expected) - expected.addAttributes([NSFontAttributeName: UIFont.boldSystemFont(ofSize: 17)], range: NSRange(location: 0, length: 1)) + expected.addAttributes([NSFontAttributeName: Font.boldSystemFont(ofSize: 17)], range: NSRange(location: 0, length: 1)) XCTAssertEqual(subject, expected) } @@ -37,7 +37,7 @@ class NSMutableAttributedString_Tests: XCTestCase { XCTAssertEqual(subject, expected) subject.setAttributes([.backgroundColor(.orange)], range: 0 ..< 3) XCTAssertNotEqual(subject, expected) - expected.setAttributes([NSBackgroundColorAttributeName: UIColor.orange], range: NSRange(location: 0, length: 3)) + expected.setAttributes([NSBackgroundColorAttributeName: Color.orange], range: NSRange(location: 0, length: 3)) XCTAssertEqual(subject, expected) } @@ -47,7 +47,7 @@ class NSMutableAttributedString_Tests: XCTestCase { XCTAssertEqual(subject, expected) subject.setAttributes([.backgroundColor(.orange)], range: NSRange(location: 2, length: 2)) XCTAssertNotEqual(subject, expected) - expected.setAttributes([NSBackgroundColorAttributeName: UIColor.orange], range: NSRange(location: 2, length: 2)) + expected.setAttributes([NSBackgroundColorAttributeName: Color.orange], range: NSRange(location: 2, length: 2)) XCTAssertEqual(subject, expected) } @@ -67,7 +67,7 @@ class NSMutableAttributedString_Tests: XCTestCase { XCTAssertEqual(subject, expected) subject.replaceCharacters(in: 0 ..< 2, with: "Chi".withBackgroundColor(.magenta)) XCTAssertNotEqual(subject, expected) - expected.replaceCharacters(in: NSRange(location: 0, length: 2), with: NSAttributedString(string: "Chi", attributes: [NSBackgroundColorAttributeName: UIColor.magenta])) + expected.replaceCharacters(in: NSRange(location: 0, length: 2), with: NSAttributedString(string: "Chi", attributes: [NSBackgroundColorAttributeName: Color.magenta])) XCTAssertEqual(subject, expected) } diff --git a/SwiftyAttributesTests/Operators_Tests.swift b/SwiftyAttributesTests/Operators_Tests.swift index 8bee293..c85a913 100644 --- a/SwiftyAttributesTests/Operators_Tests.swift +++ b/SwiftyAttributesTests/Operators_Tests.swift @@ -15,11 +15,11 @@ class Operators_Tests: XCTestCase { let lhs = "Hello".withFont(.systemFont(ofSize: 19)) let rhs = "World".withTextColor(.magenta).withBackgroundColor(.orange).withFont(.boldSystemFont(ofSize: 24)) let newString = lhs + rhs - let leftAttributes = [NSFontAttributeName: UIFont.systemFont(ofSize: 19)] as [String: NSObject] + let leftAttributes = [NSFontAttributeName: Font.systemFont(ofSize: 19)] as [String: NSObject] XCTAssertEqual(newString.attributes(at: 0, effectiveRange: nil) as! [String: NSObject], leftAttributes) - let rightAttributes = [NSForegroundColorAttributeName: UIColor.magenta, - NSBackgroundColorAttributeName: UIColor.orange, - NSFontAttributeName: UIFont.boldSystemFont(ofSize: 24)] as [String: NSObject] + let rightAttributes = [NSForegroundColorAttributeName: Color.magenta, + NSBackgroundColorAttributeName: Color.orange, + NSFontAttributeName: Font.boldSystemFont(ofSize: 24)] as [String: NSObject] XCTAssertEqual(newString.attributes(at: lhs.length + 1, effectiveRange: nil) as! [String: NSObject], rightAttributes) } diff --git a/SwiftyAttributesTests/SpellingState_Tests.swift b/SwiftyAttributesTests/SpellingState_Tests.swift new file mode 100644 index 0000000..2586b67 --- /dev/null +++ b/SwiftyAttributesTests/SpellingState_Tests.swift @@ -0,0 +1,32 @@ +// +// SpellingState_Tests.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 11/26/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +#if os(macOS) +import XCTest +import SwiftyAttributes + +class SpellingState_Tests: XCTestCase { + + func testInit_nil() { + XCTAssertNil(SpellingState(rawValue: 6)) + } + + func testInit_flags() { + XCTAssertEqual(SpellingState(rawValue: NSSpellingStateGrammarFlag)!, .grammarFlag) + XCTAssertEqual(SpellingState(rawValue: NSSpellingStateSpellingFlag)!, .spellingFlag) + XCTAssertEqual(SpellingState(rawValue: 0)!, .none) + } + + func testRawValue() { + XCTAssertEqual(SpellingState.grammarFlag.rawValue, NSSpellingStateGrammarFlag) + XCTAssertEqual(SpellingState.spellingFlag.rawValue, NSSpellingStateSpellingFlag) + XCTAssertEqual(SpellingState.none.rawValue, 0) + } + +} +#endif diff --git a/SwiftyAttributesTests/SwiftyAttributes_Tests.swift b/SwiftyAttributesTests/SwiftyAttributes_Tests.swift index 41d4ccf..8d36c45 100644 --- a/SwiftyAttributesTests/SwiftyAttributes_Tests.swift +++ b/SwiftyAttributesTests/SwiftyAttributes_Tests.swift @@ -18,9 +18,12 @@ class SwiftyAttributesTests: XCTestCase { } func testAttribute_font() { - let subject = "Hello".withFont(UIFont.boldSystemFont(ofSize: 26)) - let expected = NSAttributedString(string: "Hello", attributes: [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 26)]) + let font = Font.boldSystemFont(ofSize: 26) + let subject = "Hello".withFont(font) + let subject2 = "Hello".attributedString.withFont(font) + let expected = NSAttributedString(string: "Hello", attributes: [NSFontAttributeName: Font.boldSystemFont(ofSize: 26)]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_paragraphStyle() { @@ -28,137 +31,255 @@ class SwiftyAttributesTests: XCTestCase { style.lineSpacing = 4 style.lineBreakMode = .byTruncatingMiddle let subject = "Hello".withParagraphStyle(style) + let subject2 = "Hello".attributedString.withParagraphStyle(style) let expected = NSAttributedString(string: "Hello", attributes: [NSParagraphStyleAttributeName: style]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_textColor() { let subject = "Hello".withTextColor(.magenta) - let expected = NSAttributedString(string: "Hello", attributes: [NSForegroundColorAttributeName: UIColor.magenta]) + let subject2 = "Hello".attributedString.withTextColor(.magenta) + let expected = NSAttributedString(string: "Hello", attributes: [NSForegroundColorAttributeName: Color.magenta]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_backgroundColor() { let subject = "Hello".withBackgroundColor(.cyan) - let expected = NSAttributedString(string: "Hello", attributes: [NSBackgroundColorAttributeName: UIColor.cyan]) + let subject2 = "Hello".attributedString.withBackgroundColor(.cyan) + let expected = NSAttributedString(string: "Hello", attributes: [NSBackgroundColorAttributeName: Color.cyan]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_ligature() { let subject = "Hello".withLigatures(.none) + let subject2 = "Hello".attributedString.withLigatures(.none) let expected = NSAttributedString(string: "Hello", attributes: [NSLigatureAttributeName: NSNumber(value: Ligatures.none.rawValue)]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_kern() { let subject = "Hello".withKern(12) + let subject2 = "Hello".attributedString.withKern(12) let expected = NSAttributedString(string: "Hello", attributes: [NSKernAttributeName: NSNumber(value: 12)]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_strikethroughStyle() { let subject = "Hello".withStrikethroughStyle(.patternDashDot) - let expected = NSAttributedString(string: "Hello", attributes: [NSStrikethroughStyleAttributeName: NSNumber(value: NSUnderlineStyle.patternDashDot.rawValue)]) + let subject2 = "Hello".attributedString.withStrikethroughStyle(.patternDashDot) + let expected = NSAttributedString(string: "Hello", attributes: [NSStrikethroughStyleAttributeName: NSNumber(value: UnderlineStyle.patternDashDot.rawValue)]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_underlineStyle() { let subject = "Hello".withUnderlineStyle(.styleDouble) - let expected = NSAttributedString(string: "Hello", attributes: [NSUnderlineStyleAttributeName: NSNumber(value: NSUnderlineStyle.styleDouble.rawValue)]) + let subject2 = "Hello".attributedString.withUnderlineStyle(.styleDouble) + let expected = NSAttributedString(string: "Hello", attributes: [NSUnderlineStyleAttributeName: NSNumber(value: UnderlineStyle.styleDouble.rawValue)]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_strokeColor() { let subject = "Hello".withStrokeColor(.orange) - let expected = NSAttributedString(string: "Hello", attributes: [NSStrokeColorAttributeName: UIColor.orange]) + let subject2 = "Hello".attributedString.withStrokeColor(.orange) + let expected = NSAttributedString(string: "Hello", attributes: [NSStrokeColorAttributeName: Color.orange]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_strokeWidth() { let subject = "Hello".withStrokeWidth(3.2) + let subject2 = "Hello".attributedString.withStrokeWidth(3.2) let expected = NSAttributedString(string: "Hello", attributes: [NSStrokeWidthAttributeName: NSNumber(value: 3.2)]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_shadow() { - let shadow = NSShadow() + let shadow = Shadow() shadow.shadowBlurRadius = 4 - shadow.shadowColor = UIColor.brown + shadow.shadowColor = Color.brown let subject = "Hello".withShadow(shadow) + let subject2 = "Hello".attributedString.withShadow(shadow) let expected = NSAttributedString(string: "Hello", attributes: [NSShadowAttributeName: shadow]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_textEffect() { let subject = "Hello".withTextEffect(.letterPressStyle) + let subject2 = "Hello".attributedString.withTextEffect(.letterPressStyle) let expected = NSAttributedString(string: "Hello", attributes: [NSTextEffectAttributeName: NSTextEffectLetterpressStyle]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_attachment() { - let attachment = NSTextAttachment(data: nil, ofType: nil) + let attachment = TextAttachment(data: nil, ofType: nil) let subject = "Hello".withAttachment(attachment) + let subject2 = "Hello".attributedString.withAttachment(attachment) let expected = NSAttributedString(string: "Hello", attributes: [NSAttachmentAttributeName: attachment]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_link() { let url = URL(string: "https://google.com")! let subject = "Hello".withLink(url) + let subject2 = "Hello".attributedString.withLink(url) let expected = NSAttributedString(string: "Hello", attributes: [NSLinkAttributeName: url]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_baselineOffset() { let subject = "Hello".withBaselineOffset(5) + let subject2 = "Hello".attributedString.withBaselineOffset(5) let expected = NSAttributedString(string: "Hello", attributes: [NSBaselineOffsetAttributeName: NSNumber(value: 5)]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_underlineColor() { let subject = "Hello".withUnderlineColor(.magenta) - let expected = NSAttributedString(string: "Hello", attributes: [NSUnderlineColorAttributeName: UIColor.magenta]) + let subject2 = "Hello".attributedString.withUnderlineColor(.magenta) + let expected = NSAttributedString(string: "Hello", attributes: [NSUnderlineColorAttributeName: Color.magenta]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_strikethroughColor() { let subject = "Hello".withStrikethroughColor(.brown) - let expected = NSAttributedString(string: "Hello", attributes: [NSStrikethroughColorAttributeName: UIColor.brown]) + let subject2 = "Hello".attributedString.withStrikethroughColor(.brown) + let expected = NSAttributedString(string: "Hello", attributes: [NSStrikethroughColorAttributeName: Color.brown]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_obliqueness() { let subject = "Hello".withObliqueness(4.5) + let subject2 = "Hello".attributedString.withObliqueness(4.5) let expected = NSAttributedString(string: "Hello", attributes: [NSObliquenessAttributeName: NSNumber(value: 4.5)]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } func testAttribute_expansion() { let subject = "Hello".withExpansion(7) + let subject2 = "Hello".attributedString.withExpansion(7) let expected = NSAttributedString(string: "Hello", attributes: [NSExpansionAttributeName: NSNumber(value: 7)]) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } + func testAttribute_verticalGlyphForm() { + let subject = "Hello".withVerticalGlyphForm(.horizontal) + let subject2 = "Hello".attributedString.withVerticalGlyphForm(.horizontal) + let expected = NSAttributedString(string: "Hello", attributes: [NSVerticalGlyphFormAttributeName: NSNumber(value: 0)]) + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) + } + + @available(iOS 9.0, *) + func testAttribute_writingDirection() { + let subject = "Hello".withWritingDirections([.rightToLeftOverride]) + let subject2 = "Hello".attributedString.withWritingDirections([.rightToLeftOverride]) + let expected = NSAttributedString(string: "Hello", attributes: [NSWritingDirectionAttributeName: [NSNumber(value: NSWritingDirection.rightToLeft.rawValue | NSWritingDirectionFormatType.override.rawValue)]]) + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) + } + + #if os(macOS) + + func testAttribute_cursor() { + let cursor = Cursor(image: NSImage(), foregroundColorHint: .blue, backgroundColorHint: .red, hotSpot: NSPoint(x: 2, y: 2)) + let subject = "Hello".withCursor(cursor) + let subject2 = "Hello".attributedString.withCursor(cursor) + let expected = NSAttributedString(string: "Hello", attributes: [NSCursorAttributeName: cursor]) + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) + } + + func testAttribute_markedClauseSegment() { + let subject = "Hello".withMarkedClauseSegment(3) + let subject2 = "Hello".attributedString.withMarkedClauseSegment(3) + let expected = NSAttributedString(string: "Hello", attributes: [NSMarkedClauseSegmentAttributeName: 3]) + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) + } + + func testAttribute_spellingState_grammar() { + let subject = "Hello".withSpellingState(.grammarFlag) + let subject2 = "Hello".attributedString.withSpellingState(.grammarFlag) + let expected = NSAttributedString(string: "Hello", attributes: [NSSpellingStateAttributeName: NSSpellingStateGrammarFlag]) + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) + } + + func testAttribute_spellingState_none() { + let subject = "Hello".withSpellingState(.none) + let subject2 = "Hello".attributedString.withSpellingState(.none) + let expected = NSAttributedString(string: "Hello", attributes: [NSSpellingStateAttributeName: 0]) + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) + } + + func testAttribute_superscript() { + let subject = "Hello".withSuperscript(4) + let subject2 = "Hello".attributedString.withSuperscript(4) + let expected = NSAttributedString(string: "Hello", attributes: [NSSuperscriptAttributeName: 4]) + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) + } + + func testAttribute_textAlternatives() { + let alternatives = TextAlternatives(primaryString: "Hi", alternativeStrings: ["Yo", "Sup"]) + let subject = "Hello".withTextAlternatives(alternatives) + let subject2 = "Hello".attributedString.withTextAlternatives(alternatives) + let expected = NSAttributedString(string: "Hello", attributes: [NSTextAlternativesAttributeName: alternatives]) + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) + } + + func testAttribute_toolTip() { + let subject = "Hello".withToolTip("Sah dude") + let subject2 = "Hello".attributedString.withToolTip("Sah dude") + let expected = NSAttributedString(string: "Hello", attributes: [NSToolTipAttributeName: "Sah dude"]) + XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) + } + + #endif + func testMultipleAttributes_withSyntax() { let subject = "Hello".withTextColor(.darkGray).withBackgroundColor(.magenta).withStrikethroughStyle(.patternDashDotDot) let attrs: [String: Any] = [ - NSForegroundColorAttributeName: UIColor.darkGray, - NSBackgroundColorAttributeName: UIColor.magenta, - NSStrikethroughStyleAttributeName: NSUnderlineStyle.patternDashDotDot.rawValue + NSForegroundColorAttributeName: Color.darkGray, + NSBackgroundColorAttributeName: Color.magenta, + NSStrikethroughStyleAttributeName: UnderlineStyle.patternDashDotDot.rawValue ] let expected = NSAttributedString(string: "Hello", attributes: attrs) XCTAssertEqual(subject, expected) } func testMultipleAttributes_arraySyntax() { - let subject = "Hello".withAttributes([.font(.boldSystemFont(ofSize: 19)), .link(URL(string: "https://google.com")!), .underlineStyle(.patternSolid)]) + let attributes: [Attribute] = [.font(.boldSystemFont(ofSize: 19)), .link(URL(string: "https://google.com")!), .underlineStyle(.patternSolid)] + let subject = "Hello".withAttributes(attributes) + let subject2 = "Hello".attributedString.withAttributes(attributes) let attrs: [String: Any] = [ - NSFontAttributeName: UIFont.boldSystemFont(ofSize: 19), + NSFontAttributeName: Font.boldSystemFont(ofSize: 19), NSLinkAttributeName: URL(string: "https://google.com")!, - NSUnderlineStyleAttributeName: NSUnderlineStyle.patternSolid.rawValue + NSUnderlineStyleAttributeName: UnderlineStyle.patternSolid.rawValue ] let expected = NSAttributedString(string: "Hello", attributes: attrs) XCTAssertEqual(subject, expected) + XCTAssertEqual(subject2, expected) } } diff --git a/SwiftyAttributesTests/VerticalGlyphForm_Tests.swift b/SwiftyAttributesTests/VerticalGlyphForm_Tests.swift new file mode 100644 index 0000000..b04eb41 --- /dev/null +++ b/SwiftyAttributesTests/VerticalGlyphForm_Tests.swift @@ -0,0 +1,21 @@ +// +// VerticalGlyphForm_Tests.swift +// SwiftyAttributes +// +// Created by Eddie Kaiger on 11/29/16. +// Copyright © 2016 Eddie Kaiger. All rights reserved. +// + +import XCTest +import SwiftyAttributes + +class VerticalGlyphForm_Tests: XCTestCase { + + func testRawValue() { + XCTAssertEqual(VerticalGlyphForm.horizontal.rawValue, 0) + #if os(macOS) + XCTAssertEqual(VerticalGlyphForm.vertical.rawValue, 1) + #endif + } + +} diff --git a/codecov.yml b/codecov.yml index 5413feb..0da9ac5 100644 --- a/codecov.yml +++ b/codecov.yml @@ -7,14 +7,16 @@ comment: require_changes: false coverage: precision: 2 - range: - - 70.0 - - 99.0 + range: "70...99" round: down status: changes: false - patch: true - project: true + patch: + default: + target: 99 + project: + default: + target: 99 parsers: gcov: branch_detection: