Modernize to Swift 2.0

This commit is contained in:
Matthias Neeracher 2015-11-16 02:56:33 +01:00 committed by Matthias Neeracher
parent bc77af7a80
commit 8d7e8c8c10
11 changed files with 225 additions and 205 deletions

View File

@ -316,6 +316,7 @@
9501D7F41A17025C0034C530 /* Project object */ = { 9501D7F41A17025C0034C530 /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftMigration = 0710;
LastSwiftUpdateCheck = 0700; LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0630; LastUpgradeCheck = 0630;
ORGANIZATIONNAME = "Aere Perennius"; ORGANIZATIONNAME = "Aere Perennius";

View File

@ -10,7 +10,7 @@ import Foundation
extension ACEView { extension ACEView {
class func themeIdByName(themeName: String) -> ACETheme? { class func themeIdByName(themeName: String) -> ACETheme? {
for (themeIdx, theme) in enumerate(ACEThemeNames.themeNames() as! [String]) { for (themeIdx, theme) in (ACEThemeNames.themeNames() as! [String]).enumerate() {
if themeName == theme { if themeName == theme {
return ACETheme(rawValue: UInt(themeIdx)) return ACETheme(rawValue: UInt(themeIdx))
} }
@ -19,7 +19,7 @@ extension ACEView {
} }
class func handlerIdByName(handlerName: String) -> ACEKeyboardHandler? { class func handlerIdByName(handlerName: String) -> ACEKeyboardHandler? {
for (handlerIdx, handler) in enumerate(ACEKeyboardHandlerNames.humanKeyboardHandlerNames() as! [String]) { for (handlerIdx, handler) in (ACEKeyboardHandlerNames.humanKeyboardHandlerNames() as! [String]).enumerate() {
if handlerName == handler { if handlerName == handler {
return ACEKeyboardHandler(rawValue: UInt(handlerIdx))! return ACEKeyboardHandler(rawValue: UInt(handlerIdx))!
} }

View File

@ -18,11 +18,7 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
var examples = [String]() var examples = [String]()
func hasDocument() -> Bool { func hasDocument() -> Bool {
if let doc = NSDocumentController.sharedDocumentController().currentDocument as? NSDocument { return NSDocumentController.sharedDocumentController().currentDocument != nil
return true
} else {
return false
}
} }
func applicationWillFinishLaunching(notification: NSNotification) { func applicationWillFinishLaunching(notification: NSNotification) {
@ -56,12 +52,12 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
} }
func applicationDidFinishLaunching(aNotification: NSNotification) { func applicationDidFinishLaunching(aNotification: NSNotification) {
themeMenu.removeAllItems() themeMenu.removeAllItems()
for (index, theme) in enumerate(ACEThemeNames.humanThemeNames() as! [String]) { for (index, theme) in (ACEThemeNames.humanThemeNames() as! [String]).enumerate() {
let menuItem = themeMenu.addItemWithTitle(theme, action: "changeTheme:", keyEquivalent: "")! let menuItem = themeMenu.addItemWithTitle(theme, action: "changeTheme:", keyEquivalent: "")!
menuItem.tag = index menuItem.tag = index
} }
keyboardMenu.removeAllItems() keyboardMenu.removeAllItems()
for (index, theme) in enumerate(ACEKeyboardHandlerNames.humanKeyboardHandlerNames() as! [String]) { for (index, theme) in (ACEKeyboardHandlerNames.humanKeyboardHandlerNames() as! [String]).enumerate() {
let menuItem = keyboardMenu.addItemWithTitle(theme, action: "changeKeyboardHandler:", keyEquivalent: "")! let menuItem = keyboardMenu.addItemWithTitle(theme, action: "changeKeyboardHandler:", keyEquivalent: "")!
menuItem.tag = index menuItem.tag = index
} }
@ -85,8 +81,8 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
case "Examples": case "Examples":
menu.removeAllItems() menu.removeAllItems()
examples = [String]() examples = [String]()
if let arduinoPath = NSWorkspace.sharedWorkspace().URLForApplicationWithBundleIdentifier("cc.arduino.Arduino")?.path { if let arduinoURL = NSWorkspace.sharedWorkspace().URLForApplicationWithBundleIdentifier("cc.arduino.Arduino") {
let examplePath = arduinoPath.stringByAppendingPathComponent("Contents/Resources/Java/examples") let examplePath = arduinoURL.URLByAppendingPathComponent("Contents/Resources/Java/examples", isDirectory:true).path!
ASSketchBook.addSketches(menu, target: self, action: "openExample:", path: examplePath, sketches: &examples) ASSketchBook.addSketches(menu, target: self, action: "openExample:", path: examplePath, sketches: &examples)
} }
case "Import Standard Library": case "Import Standard Library":
@ -100,7 +96,7 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
while menu.numberOfItems > 2 { while menu.numberOfItems > 2 {
menu.removeItemAtIndex(2) menu.removeItemAtIndex(2)
} }
for port in ASSerial.ports() as! [String] { for port in ASSerial.ports() {
menu.addItemWithTitle(port, action:"serialConnectMenu:", keyEquivalent:"") menu.addItemWithTitle(port, action:"serialConnectMenu:", keyEquivalent:"")
} }
default: default:
@ -119,28 +115,26 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
let oldName = template.lastPathComponent! let oldName = template.lastPathComponent!
let newName = saveTo.lastPathComponent! let newName = saveTo.lastPathComponent!
let fileManager = NSFileManager.defaultManager() let fileManager = NSFileManager.defaultManager()
fileManager.copyItemAtURL(template, toURL: saveTo, error: nil) do {
try fileManager.copyItemAtURL(template, toURL: saveTo)
let contents = fileManager.enumeratorAtURL(saveTo, let contents = fileManager.enumeratorAtURL(saveTo,
includingPropertiesForKeys: [NSURLNameKey, NSURLPathKey], includingPropertiesForKeys: [NSURLNameKey, NSURLPathKey],
options: .SkipsHiddenFiles, errorHandler: nil) options: .SkipsHiddenFiles, errorHandler: nil)
while let item = contents?.nextObject() as? NSURL { while let item = contents?.nextObject() as? NSURL {
var renameItem = false let itemBase = item.URLByDeletingPathExtension?.lastPathComponent!
var itemName = item.lastPathComponent! if itemBase == oldName {
if itemName.stringByDeletingPathExtension == oldName { let newItem = item.URLByDeletingLastPathComponent!.URLByAppendingPathComponent(
renameItem = true newName).URLByAppendingPathExtension(item.pathExtension!)
itemName = newName.stringByAppendingPathExtension(itemName.pathExtension)! try fileManager.moveItemAtURL(item, toURL: newItem)
} }
if renameItem {
fileManager.moveItemAtURL(item,
toURL: item.URLByDeletingLastPathComponent!.URLByAppendingPathComponent(itemName),
error: nil)
} }
} catch (_) {
} }
let sketch = ASSketchBook.findSketch(saveTo.path!) let sketch = ASSketchBook.findSketch(saveTo.path!)
switch sketch { switch sketch {
case .Sketch(_, let path): case .Sketch(_, let path):
let doc = NSDocumentController.sharedDocumentController() as! NSDocumentController let doc = NSDocumentController.sharedDocumentController()
doc.openDocumentWithContentsOfURL(NSURL(fileURLWithPath: path)!, display: true) { (doc, alreadyOpen, error) -> Void in doc.openDocumentWithContentsOfURL(NSURL(fileURLWithPath: path), display: true) { (doc, alreadyOpen, error) -> Void in
} }
default: default:
break break
@ -149,39 +143,40 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
} }
@IBAction func openSketch(item: NSMenuItem) { @IBAction func openSketch(item: NSMenuItem) {
if let url = NSURL(fileURLWithPath: sketches[item.tag]) { let url = NSURL(fileURLWithPath: sketches[item.tag])
let doc = NSDocumentController.sharedDocumentController() as! NSDocumentController let doc = NSDocumentController.sharedDocumentController()
doc.openDocumentWithContentsOfURL(url, display: true) { (doc, alreadyOpen, error) -> Void in doc.openDocumentWithContentsOfURL(url, display: true) { (doc, alreadyOpen, error) -> Void in
} }
} }
}
@IBAction func openExample(item: NSMenuItem) { @IBAction func openExample(item: NSMenuItem) {
if let url = NSURL(fileURLWithPath: examples[item.tag]) { let url = NSURL(fileURLWithPath: examples[item.tag])
openTemplate(url.URLByDeletingLastPathComponent!) openTemplate(url.URLByDeletingLastPathComponent!)
} }
}
@IBAction func createSketch(AnyObject) { @IBAction func createSketch(_: AnyObject) {
ASApplication.newProjectLocation(nil, ASApplication.newProjectLocation(nil,
message: "Create Project") message: "Create Project")
{ (saveTo) -> Void in { (saveTo) -> Void in
let fileManager = NSFileManager.defaultManager() let fileManager = NSFileManager.defaultManager()
fileManager.createDirectoryAtURL(saveTo, withIntermediateDirectories:false, attributes:nil, error:nil) do {
try fileManager.createDirectoryAtURL(saveTo, withIntermediateDirectories:false, attributes:nil)
let proj = saveTo.URLByAppendingPathComponent(saveTo.lastPathComponent!+".avrsackproj") let proj = saveTo.URLByAppendingPathComponent(saveTo.lastPathComponent!+".avrsackproj")
let docController = NSDocumentController.sharedDocumentController() as! NSDocumentController let docController = NSDocumentController.sharedDocumentController()
if let doc = docController.openUntitledDocumentAndDisplay(true, error:nil) as? ASProjDoc { if let doc = try docController.openUntitledDocumentAndDisplay(true) as? ASProjDoc {
doc.fileURL = proj doc.fileURL = proj
doc.updateProjectURL() doc.updateProjectURL()
doc.createFileAtURL(saveTo.URLByAppendingPathComponent(saveTo.lastPathComponent!+".ino")) doc.createFileAtURL(saveTo.URLByAppendingPathComponent(saveTo.lastPathComponent!+".ino"))
doc.writeToURL(proj, ofType: "Project", forSaveOperation: .SaveAsOperation, originalContentsURL: nil, error: nil) try doc.writeToURL(proj, ofType: "Project", forSaveOperation: .SaveAsOperation, originalContentsURL: nil)
}
} catch _ {
} }
} }
} }
class func newProjectLocation(documentWindow: NSWindow?, message: String, completion: (NSURL) -> ()) { class func newProjectLocation(documentWindow: NSWindow?, message: String, completion: (NSURL) -> ()) {
let savePanel = NSSavePanel() let savePanel = NSSavePanel()
savePanel.allowedFileTypes = [kUTTypeFolder] savePanel.allowedFileTypes = [kUTTypeFolder as String]
savePanel.message = message savePanel.message = message
if let window = documentWindow { if let window = documentWindow {
savePanel.beginSheetModalForWindow(window, completionHandler: { (returnCode) -> Void in savePanel.beginSheetModalForWindow(window, completionHandler: { (returnCode) -> Void in

View File

@ -17,7 +17,7 @@ class ASBuilder {
init() { init() {
termination = NSNotificationCenter.defaultCenter().addObserverForName(NSTaskDidTerminateNotification, termination = NSNotificationCenter.defaultCenter().addObserverForName(NSTaskDidTerminateNotification,
object: nil, queue: nil, usingBlock: object: nil, queue: nil, usingBlock:
{ (notification: NSNotification!) in { (notification: NSNotification) in
if notification.object as? NSTask == self.task { if notification.object as? NSTask == self.task {
if self.task!.terminationStatus == 0 { if self.task!.terminationStatus == 0 {
if let cont = self.continuation { if let cont = self.continuation {
@ -44,7 +44,10 @@ class ASBuilder {
} }
func cleanProject() { func cleanProject() {
NSFileManager.defaultManager().removeItemAtURL(dir.URLByAppendingPathComponent("build"), error: nil) do {
try NSFileManager.defaultManager().removeItemAtURL(dir.URLByAppendingPathComponent("build"))
} catch _ {
}
} }
func buildProject(board: String, files: ASFileTree) { func buildProject(board: String, files: ASFileTree) {
@ -62,7 +65,7 @@ class ASBuilder {
} }
let boardProp = ASHardware.instance().boards[board]! let boardProp = ASHardware.instance().boards[board]!
let library = boardProp["library"]! let library = boardProp["library"]!
var corePath = library+"/cores/"+boardProp["build.core"]! let corePath = library+"/cores/"+boardProp["build.core"]!
var variantPath : String? var variantPath : String?
if fileManager.fileExistsAtPath(corePath) { if fileManager.fileExistsAtPath(corePath) {
if let variantName = boardProp["build.variant"] { if let variantName = boardProp["build.variant"] {
@ -186,7 +189,7 @@ class ASBuilder {
task2.standardOutput = logOut task2.standardOutput = logOut
task2.standardError = logOut task2.standardError = logOut
continuation = { continuation = {
let cmdLine = task2.launchPath+" "+(loaderArgs as NSArray).componentsJoinedByString(" ")+"\n" let cmdLine = task2.launchPath!+" "+(loaderArgs as NSArray).componentsJoinedByString(" ")+"\n"
logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!) logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
task2.launch() task2.launch()
self.continuation = { self.continuation = {
@ -226,12 +229,12 @@ class ASBuilder {
} }
} }
} }
let cmdLine = task!.launchPath+" "+(args as NSArray).componentsJoinedByString(" ")+"\n" let cmdLine = task!.launchPath!+" "+(args as NSArray).componentsJoinedByString(" ")+"\n"
logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!) logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
task!.arguments = args; task!.arguments = args;
task!.launch() task!.launch()
if interactive { if interactive {
let intSpeed = speed?.toInt() ?? 19200 let intSpeed = (speed != nil) ? Int(speed!) ?? 19200 : 19200
ASSerialWin.showWindowWithPort(port, task:task!, speed:intSpeed) ASSerialWin.showWindowWithPort(port, task:task!, speed:intSpeed)
task = nil task = nil
} }
@ -253,7 +256,7 @@ class ASBuilder {
let showSource = NSUserDefaults.standardUserDefaults().boolForKey("ShowSourceInDisassembly") let showSource = NSUserDefaults.standardUserDefaults().boolForKey("ShowSourceInDisassembly")
var args = showSource ? ["-S"] : [] var args = showSource ? ["-S"] : []
args += ["-d", "build/"+board+"/"+dir.lastPathComponent!+".elf"] args += ["-d", "build/"+board+"/"+dir.lastPathComponent!+".elf"]
let cmdLine = task!.launchPath+" "+(args as NSArray).componentsJoinedByString(" ")+"\n" let cmdLine = task!.launchPath!+" "+(args as NSArray).componentsJoinedByString(" ")+"\n"
logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!) logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
task!.arguments = args; task!.arguments = args;
task!.launch() task!.launch()

View File

@ -54,12 +54,7 @@ private let kNodeTypeGroup = "Group"
private let kNodeTypeFile = "File" private let kNodeTypeFile = "File"
private let kNameKey = "Name" private let kNameKey = "Name"
// class ASFileNode {
// <rdar://problem/19787270> At the moment, Swift crashes at link time with an assertion
// if anything other than a value type or an @objc class is put into a container
// exposed to ObjC APIs. As a workaround, we declare this hierarchy @objc
//
@objc class ASFileNode {
var name : String var name : String
init(name: String) { init(name: String) {
@ -192,7 +187,7 @@ class ASFileItem : ASFileNode {
if let relativeURL = NSURL(string: prop[kPathKey] as! String, relativeToURL: rootURL) { if let relativeURL = NSURL(string: prop[kPathKey] as! String, relativeToURL: rootURL) {
url = relativeURL.URLByStandardizingPath! url = relativeURL.URLByStandardizingPath!
} else { } else {
url = NSURL(fileURLWithPath:(prop[kPathKey] as! String))!.URLByStandardizingPath! url = NSURL(fileURLWithPath:(prop[kPathKey] as! String)).URLByStandardizingPath!
} }
if !url.checkResourceIsReachableAndReturnError(nil) { if !url.checkResourceIsReachableAndReturnError(nil) {
// //
@ -200,10 +195,11 @@ class ASFileItem : ASFileNode {
// yet reflected in the project file. // yet reflected in the project file.
// //
let urlDir = url.URLByDeletingLastPathComponent let urlDir = url.URLByDeletingLastPathComponent
let newName = rootURL.lastPathComponent!.stringByAppendingPathExtension(url.pathExtension!)! let newName = rootURL.URLByAppendingPathExtension(url.pathExtension!).lastPathComponent!
let altURL = urlDir?.URLByAppendingPathComponent(newName) if let altURL = urlDir?.URLByAppendingPathComponent(newName) {
if altURL != nil && altURL!.checkResourceIsReachableAndReturnError(nil) { if altURL.checkResourceIsReachableAndReturnError(nil) {
url = altURL! url = altURL
}
} }
} }
super.init(name:url.lastPathComponent!) super.init(name:url.lastPathComponent!)
@ -213,7 +209,7 @@ class ASFileItem : ASFileNode {
} }
func relativePath(relativeTo: String) -> String { func relativePath(relativeTo: String) -> String {
let path = url.path!.stringByResolvingSymlinksInPath let path = (url.path! as NSString).stringByResolvingSymlinksInPath
let relComp = relativeTo.componentsSeparatedByString("/") as [String] let relComp = relativeTo.componentsSeparatedByString("/") as [String]
let pathComp = path.componentsSeparatedByString("/") as [String] let pathComp = path.componentsSeparatedByString("/") as [String]
let relCount = relComp.count let relCount = relComp.count
@ -232,7 +228,7 @@ class ASFileItem : ASFileNode {
} }
let resComp = Array(count: relCount-matchComp, repeatedValue: "..")+pathComp[matchComp..<pathCount] let resComp = Array(count: relCount-matchComp, repeatedValue: "..")+pathComp[matchComp..<pathCount]
return "/".join(resComp) return resComp.joinWithSeparator("/")
} }
override func propertyList(rootPath: String) -> AnyObject { override func propertyList(rootPath: String) -> AnyObject {
return [kTypeKey: kNodeTypeFile, kKindKey: type.rawValue, kPathKey: relativePath(rootPath)] return [kTypeKey: kNodeTypeFile, kKindKey: type.rawValue, kPathKey: relativePath(rootPath)]
@ -245,8 +241,12 @@ class ASFileItem : ASFileNode {
} }
override func modDate() -> NSDate? { override func modDate() -> NSDate? {
var date: AnyObject? var date: AnyObject?
url.getResourceValue(&date, forKey: NSURLContentModificationDateKey, error: nil) do {
try url.getResourceValue(&date, forKey: NSURLContentModificationDateKey)
return date as? NSDate return date as? NSDate
} catch _ {
return nil
}
} }
override func revision() -> String? { override func revision() -> String? {
let task = NSTask() let task = NSTask()
@ -276,11 +276,11 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
} }
} }
func setProjectURL(url: NSURL) { func setProjectURL(url: NSURL) {
root.name = url.lastPathComponent!.stringByDeletingPathExtension root.name = url.URLByDeletingPathExtension!.lastPathComponent!
dir = url.URLByDeletingLastPathComponent!.URLByStandardizingPath! dir = url.URLByDeletingLastPathComponent!.URLByStandardizingPath!
} }
func projectPath() -> String { func projectPath() -> String {
return dir.path!.stringByResolvingSymlinksInPath return (dir.path! as NSString).stringByResolvingSymlinksInPath
} }
func apply(closure: (ASFileNode) -> ()) { func apply(closure: (ASFileNode) -> ()) {
root.apply(closure) root.apply(closure)

View File

@ -13,7 +13,7 @@ typealias ASProperties = [String: ASPropertyEntry]
extension NSMenu { extension NSMenu {
func addSortedChoices(choices:[ASPropertyEntry], target: AnyObject, selector: Selector) { func addSortedChoices(choices:[ASPropertyEntry], target: AnyObject, selector: Selector) {
for choice in choices.sorted({ $0["name"] < $1["name"] }) { for choice in choices.sort({ $0["name"] < $1["name"] }) {
let item = self.addItemWithTitle(choice["name"]!, action: selector, keyEquivalent: "") let item = self.addItemWithTitle(choice["name"]!, action: selector, keyEquivalent: "")
item?.target = target item?.target = target
} }
@ -24,8 +24,8 @@ private func subdirectories(path: String) -> [String] {
let fileManager = NSFileManager.defaultManager() let fileManager = NSFileManager.defaultManager()
var subDirs = [String]() var subDirs = [String]()
var isDir : ObjCBool = false var isDir : ObjCBool = false
if fileManager.fileExistsAtPath(path, isDirectory: &isDir) && isDir { if let items = try? fileManager.contentsOfDirectoryAtPath(path) {
for item in fileManager.contentsOfDirectoryAtPath(path, error: nil) as! [String] { for item in items {
let subPath = path+"/"+item let subPath = path+"/"+item
if fileManager.fileExistsAtPath(subPath, isDirectory: &isDir) && isDir { if fileManager.fileExistsAtPath(subPath, isDirectory: &isDir) && isDir {
subDirs.append(subPath) subDirs.append(subPath)
@ -46,7 +46,6 @@ class ASHardware {
// Gather hardware directories // Gather hardware directories
// //
let userDefaults = NSUserDefaults.standardUserDefaults() let userDefaults = NSUserDefaults.standardUserDefaults()
let fileManager = NSFileManager.defaultManager()
if let arduinoPath = userDefaults.stringForKey("Arduino") { if let arduinoPath = userDefaults.stringForKey("Arduino") {
let arduinoHardwarePath = arduinoPath + "/Contents/Resources/Java/hardware" let arduinoHardwarePath = arduinoPath + "/Contents/Resources/Java/hardware"
directories += subdirectories(arduinoHardwarePath) directories += subdirectories(arduinoHardwarePath)
@ -55,20 +54,21 @@ class ASHardware {
let hardwarePath = sketchDir + "/hardware" let hardwarePath = sketchDir + "/hardware"
directories += subdirectories(hardwarePath) directories += subdirectories(hardwarePath)
} }
let property = NSRegularExpression(pattern: "\\s*(\\w+)\\.(\\S+?)\\s*=\\s*(\\S.*\\S)\\s*", options: nil, error: nil)! let property = try! NSRegularExpression(pattern: "\\s*(\\w+)\\.(\\S+?)\\s*=\\s*(\\S.*\\S)\\s*", options: [])
// //
// Gather board declarations // Gather board declarations
// //
for dir in directories { for dir in directories {
let boardsPath = dir+"/boards.txt" let boardsPath = dir+"/boards.txt"
let provenience = dir.lastPathComponent let provenience = (dir as NSString).lastPathComponent
if let boardsFile = NSString(contentsOfFile: boardsPath, usedEncoding: nil, error: nil) { if let boardsFile = try? NSString(contentsOfFile: boardsPath, usedEncoding: nil) {
var seen = [String: Bool]() var seen = [String: Bool]()
for line in boardsFile.componentsSeparatedByString("\n") as! [NSString] { for line in boardsFile.componentsSeparatedByString("\n") {
if let match = property.firstMatchInString(line as String, options: .Anchored, range: NSMakeRange(0, line.length)) { if let match = property.firstMatchInString(line, options: .Anchored, range: NSMakeRange(0, line.utf16.count)) {
let board = line.substringWithRange(match.rangeAtIndex(1)) as String let nsline = line as NSString
let property = line.substringWithRange(match.rangeAtIndex(2)) as String let board = nsline.substringWithRange(match.rangeAtIndex(1)) as String
let value = line.substringWithRange(match.rangeAtIndex(3)) as String let property = nsline.substringWithRange(match.rangeAtIndex(2)) as String
let value = nsline.substringWithRange(match.rangeAtIndex(3)) as String
if seen.updateValue(true, forKey: board) == nil { if seen.updateValue(true, forKey: board) == nil {
boards[board] = ASPropertyEntry() boards[board] = ASPropertyEntry()
boards[board]!["provenience"] = provenience boards[board]!["provenience"] = provenience
@ -85,14 +85,15 @@ class ASHardware {
// //
for dir in directories { for dir in directories {
let programmersPath = dir+"/programmers.txt" let programmersPath = dir+"/programmers.txt"
let provenience = dir.lastPathComponent let provenience = (dir as NSString).lastPathComponent
if let programmersFile = NSString(contentsOfFile: programmersPath, usedEncoding: nil, error: nil) { if let programmersFile = try? NSString(contentsOfFile: programmersPath, usedEncoding: nil) {
var seen = [String: Bool]() var seen = [String: Bool]()
for line in programmersFile.componentsSeparatedByString("\n") as! [NSString] { for line in programmersFile.componentsSeparatedByString("\n") {
if let match = property.firstMatchInString(line as String, options: .Anchored, range: NSMakeRange(0, line.length)) { if let match = property.firstMatchInString(line, options: .Anchored, range: NSMakeRange(0, line.utf16.count)) {
let programmer = line.substringWithRange(match.rangeAtIndex(1)) let nsline = line as NSString
let property = line.substringWithRange(match.rangeAtIndex(2)) let programmer = nsline.substringWithRange(match.rangeAtIndex(1))
let value = line.substringWithRange(match.rangeAtIndex(3)) let property = nsline.substringWithRange(match.rangeAtIndex(2))
let value = nsline.substringWithRange(match.rangeAtIndex(3))
if seen.updateValue(true, forKey: programmer) == nil { if seen.updateValue(true, forKey: programmer) == nil {
programmers[programmer] = ASPropertyEntry() programmers[programmer] = ASPropertyEntry()
programmers[programmer]!["provenience"] = provenience programmers[programmer]!["provenience"] = provenience
@ -117,7 +118,7 @@ class ASHardware {
seen[prop["provenience"]!] = true seen[prop["provenience"]!] = true
} }
var sortedKeys = [String](seen.keys) var sortedKeys = [String](seen.keys)
sortedKeys.sort { $0 < $1 } sortedKeys.sortInPlace { $0 < $1 }
for provenience in sortedKeys { for provenience in sortedKeys {
var subset = [ASPropertyEntry]() var subset = [ASPropertyEntry]()
for prop in choices.values { for prop in choices.values {
@ -155,7 +156,6 @@ class ASLibraries : NSObject {
// Gather hardware directories // Gather hardware directories
// //
let userDefaults = NSUserDefaults.standardUserDefaults() let userDefaults = NSUserDefaults.standardUserDefaults()
let fileManager = NSFileManager.defaultManager()
for sketchDir in userDefaults.objectForKey("Sketchbooks") as! [String] { for sketchDir in userDefaults.objectForKey("Sketchbooks") as! [String] {
let librariesPath = sketchDir + "/libraries" let librariesPath = sketchDir + "/libraries"
let dirs = subdirectories(librariesPath) let dirs = subdirectories(librariesPath)
@ -176,15 +176,15 @@ class ASLibraries : NSObject {
} }
} }
func addStandardLibrariesToMenu(menu: NSMenu) { func addStandardLibrariesToMenu(menu: NSMenu) {
for (index,lib) in enumerate(standardLib) { for (index,lib) in standardLib.enumerate() {
let menuItem = menu.addItemWithTitle(lib.lastPathComponent, action: "importStandardLibrary:", keyEquivalent: "") let menuItem = menu.addItemWithTitle((lib as NSString).lastPathComponent, action: "importStandardLibrary:", keyEquivalent: "")
menuItem?.target = self menuItem?.target = self
menuItem?.tag = index menuItem?.tag = index
} }
} }
func addContribLibrariesToMenu(menu: NSMenu) { func addContribLibrariesToMenu(menu: NSMenu) {
for (index,lib) in enumerate(contribLib) { for (index,lib) in contribLib.enumerate() {
let menuItem = menu.addItemWithTitle(lib.lastPathComponent, action: "importContribLibrary:", keyEquivalent: "") let menuItem = menu.addItemWithTitle((lib as NSString).lastPathComponent, action: "importContribLibrary:", keyEquivalent: "")
menuItem?.target = self menuItem?.target = self
menuItem?.tag = index menuItem?.tag = index
} }

View File

@ -14,7 +14,7 @@ private var keyboardHandler : ACEKeyboardHandler = .Ace
func pushToFront(inout list: [String], front: String) { func pushToFront(inout list: [String], front: String) {
let kMaxRecents = 8 let kMaxRecents = 8
if let existing = find(list, front) { if let existing = list.indexOf(front) {
if existing == 0 { if existing == 0 {
return return
} else { } else {
@ -48,7 +48,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
dynamic var port : String = "" dynamic var port : String = ""
var recentBoards = [String]() var recentBoards = [String]()
var recentProgrammers = [String]() var recentProgrammers = [String]()
var logModified = NSDate.distantPast() as! NSDate var logModified = NSDate.distantPast()
var logSize = 0 var logSize = 0
var updateLogTimer : NSTimer? var updateLogTimer : NSTimer?
var printingDone : () -> () = {} var printingDone : () -> () = {}
@ -93,7 +93,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
recentBoards = userDefaults.objectForKey(kRecentBoardsKey) as! [String] recentBoards = userDefaults.objectForKey(kRecentBoardsKey) as! [String]
recentProgrammers = userDefaults.objectForKey(kRecentProgrammersKey) as! [String] recentProgrammers = userDefaults.objectForKey(kRecentProgrammersKey) as! [String]
var nc = NSNotificationCenter.defaultCenter() let nc = NSNotificationCenter.defaultCenter()
themeObserver = nc.addObserverForName(kBindingsKey, object: nil, queue: nil, usingBlock: { (NSNotification) in themeObserver = nc.addObserverForName(kBindingsKey, object: nil, queue: nil, usingBlock: { (NSNotification) in
self.editor?.setKeyboardHandler(keyboardHandler) self.editor?.setKeyboardHandler(keyboardHandler)
}) })
@ -155,11 +155,14 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
func saveCurEditor() { func saveCurEditor() {
if let file = (mainEditor as? ASFileItem) { if let file = (mainEditor as? ASFileItem) {
editor.string().writeToURL(file.url, atomically: true, encoding: NSUTF8StringEncoding, error: nil) do {
try editor.string().writeToURL(file.url, atomically: true, encoding: NSUTF8StringEncoding)
} catch _ {
}
} }
} }
override func dataOfType(typeName: String, error outError: NSErrorPointer) -> NSData? { override func dataOfType(typeName: String) throws -> NSData {
let data = [kVersionKey: kCurVersion, let data = [kVersionKey: kCurVersion,
kThemeKey: ACEThemeNames.nameForTheme(currentTheme), kThemeKey: ACEThemeNames.nameForTheme(currentTheme),
kFontSizeKey: fontSize, kFontSizeKey: fontSize,
@ -170,7 +173,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
kRecentBoardsKey: recentBoards, kRecentBoardsKey: recentBoards,
kRecentProgrammersKey: recentProgrammers kRecentProgrammersKey: recentProgrammers
] ]
return NSPropertyListSerialization.dataWithPropertyList(data, format:.XMLFormat_v1_0, options:0, error:nil) return try NSPropertyListSerialization.dataWithPropertyList(data, format:.XMLFormat_v1_0, options:0)
} }
func updateProjectURL() { func updateProjectURL() {
@ -178,44 +181,40 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
builder.setProjectURL(fileURL!) builder.setProjectURL(fileURL!)
} }
func importProject(url: NSURL, error outError: NSErrorPointer) -> Bool { func importProject(url: NSURL) throws {
let existingProject = url.URLByAppendingPathComponent(url.lastPathComponent!+".avrsackproj") let existingProject = url.URLByAppendingPathComponent(url.lastPathComponent!+".avrsackproj")
if existingProject.checkResourceIsReachableAndReturnError(nil) { if existingProject.checkResourceIsReachableAndReturnError(nil) {
fileURL = existingProject fileURL = existingProject
return readFromURL(existingProject, ofType:"Project", error:outError) try readFromURL(existingProject, ofType:"Project")
return
} }
let filesInProject = let filesInProject =
NSFileManager.defaultManager().contentsOfDirectoryAtURL(url, includingPropertiesForKeys: nil, (try NSFileManager.defaultManager().contentsOfDirectoryAtURL(url, includingPropertiesForKeys: nil,
options: .SkipsHiddenFiles, error: nil) as! [NSURL] options: .SkipsHiddenFiles))
updateProjectURL() updateProjectURL()
for file in filesInProject { for file in filesInProject {
files.addFileURL(file) files.addFileURL(file)
} }
return true
} }
override func readFromURL(url: NSURL, ofType typeName: String, error outError: NSErrorPointer) -> Bool { override func readFromURL(url: NSURL, ofType typeName: String) throws {
var success : Bool = false
if typeName == "Arduino Source File" { if typeName == "Arduino Source File" {
let projectURL = url.URLByDeletingPathExtension!.URLByAppendingPathExtension("avrsackproj") let projectURL = url.URLByDeletingPathExtension!.URLByAppendingPathExtension("avrsackproj")
success = importProject(url.URLByDeletingLastPathComponent!, error: outError) try importProject(url.URLByDeletingLastPathComponent!)
if success {
fileURL = projectURL fileURL = projectURL
success = writeToURL(projectURL, ofType: "Project", forSaveOperation: .SaveAsOperation, originalContentsURL: nil, error: outError) try writeToURL(projectURL, ofType: "Project", forSaveOperation: .SaveAsOperation, originalContentsURL: nil)
}
} else { } else {
fileURL = url fileURL = url
success = super.readFromURL(url, ofType: typeName, error: outError) try super.readFromURL(url, ofType: typeName)
} }
return success
} }
override func readFromData(data: NSData, ofType typeName: String, error outError: NSErrorPointer) -> Bool { override func readFromData(data: NSData, ofType typeName: String) throws {
if typeName != ("Project" as String) { if typeName != ("Project" as String) {
return false throw NSError(domain: "AVRSack", code: 0, userInfo: nil)
} }
updateProjectURL() updateProjectURL()
let projectData = let projectData =
NSPropertyListSerialization.propertyListWithData(data, options:0, format:nil, error:nil) as! NSDictionary (try NSPropertyListSerialization.propertyListWithData(data, options:[], format:nil)) as! NSDictionary
let projectVersion = projectData[kVersionKey] as! Double let projectVersion = projectData[kVersionKey] as! Double
assert(projectVersion <= floor(kCurVersion+1.0), "Project version too new for this app") assert(projectVersion <= floor(kCurVersion+1.0), "Project version too new for this app")
if let themeName = projectData[kThemeKey] as? String { if let themeName = projectData[kThemeKey] as? String {
@ -233,8 +232,6 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
recentBoards = (projectData[kRecentBoardsKey] as? [String]) ?? recentBoards recentBoards = (projectData[kRecentBoardsKey] as? [String]) ?? recentBoards
recentProgrammers = (projectData[kRecentProgrammersKey] as? [String]) ?? recentProgrammers recentProgrammers = (projectData[kRecentProgrammersKey] as? [String]) ?? recentProgrammers
updateChangeCount(.ChangeCleared) updateChangeCount(.ChangeCleared)
return true
} }
override func duplicateDocument(sender: AnyObject?) { override func duplicateDocument(sender: AnyObject?) {
@ -242,7 +239,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
app.openTemplate(fileURL!.URLByDeletingLastPathComponent!) app.openTemplate(fileURL!.URLByDeletingLastPathComponent!)
} }
func updateLog(AnyObject?) { func updateLog(_: AnyObject?) {
if let logNode = mainEditor as? ASLogNode { if let logNode = mainEditor as? ASLogNode {
let url = fileURL?.URLByDeletingLastPathComponent?.URLByAppendingPathComponent(logNode.path) let url = fileURL?.URLByDeletingLastPathComponent?.URLByAppendingPathComponent(logNode.path)
if url == nil { if url == nil {
@ -250,16 +247,16 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
} }
var modified : AnyObject? var modified : AnyObject?
var size : AnyObject? var size : AnyObject?
if (!url!.getResourceValue(&modified, forKey:NSURLAttributeModificationDateKey, error:nil)) { do {
return try url!.getResourceValue(&modified, forKey:NSURLAttributeModificationDateKey)
} try url!.getResourceValue(&size, forKey:NSURLFileSizeKey)
if (!url!.getResourceValue(&size, forKey:NSURLFileSizeKey, error:nil)) { } catch (_) {
return return
} }
if (modified as! NSDate).compare(logModified) == .OrderedDescending || (size as! Int) != logSize { if (modified as! NSDate).compare(logModified) == .OrderedDescending || (size as! Int) != logSize {
var enc : UInt = 0 var enc : UInt = 0
let newText = NSString(contentsOfURL:url!, usedEncoding:&enc, error:nil) let newText = try? NSString(contentsOfURL:url!, usedEncoding:&enc)
editor.setString((newText as? String) ?? "") editor.setString((newText as? String) ?? "")
editor.gotoLine(1000000000, column: 0, animated: true) editor.gotoLine(1000000000, column: 0, animated: true)
logModified = modified as! NSDate logModified = modified as! NSDate
@ -274,15 +271,16 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
} }
if let file = (selection as? ASFileItem) { if let file = (selection as? ASFileItem) {
var enc : UInt = 0 var enc : UInt = 0
editor.setString(NSString(contentsOfURL:file.url, usedEncoding:&enc, error:nil) as? String ?? "") let contents = try? NSString(contentsOfURL:file.url, usedEncoding:&enc)
editor.setString(contents as? String ?? "")
editor.setMode(file.type.aceMode) editor.setMode(file.type.aceMode)
editor.alphaValue = 1.0 editor.alphaValue = 1.0
mainEditor = selection mainEditor = selection
} else if let log = (selection as? ASLogNode) { } else if selection is ASLogNode {
editor.setString("") editor.setString("")
editor.setMode(.Text) editor.setMode(.Text)
editor.alphaValue = 0.8 editor.alphaValue = 0.8
logModified = NSDate.distantPast() as! NSDate logModified = NSDate.distantPast()
logSize = -1 logSize = -1
mainEditor = selection mainEditor = selection
updateLog(nil) updateLog(nil)
@ -306,18 +304,20 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
// MARK: Printing // MARK: Printing
override func printDocumentWithSettings(printSettings: [NSObject : AnyObject], showPrintPanel: Bool, delegate: AnyObject?, didPrintSelector: Selector, contextInfo: UnsafeMutablePointer<Void>) { override func printDocumentWithSettings(printSettings: [String : AnyObject], showPrintPanel: Bool, delegate: AnyObject?, didPrintSelector: Selector, contextInfo: UnsafeMutablePointer<Void>) {
printingDone = printingDone =
{ () -> () in { () -> () in
InvokeCallback(delegate, didPrintSelector, contextInfo); InvokeCallback(delegate, didPrintSelector, contextInfo);
} }
if let logNode = mainEditor as? ASLogNode { if let logNode = mainEditor as? ASLogNode {
let url = fileURL!.URLByDeletingLastPathComponent?.URLByAppendingPathComponent(logNode.path)
var modified : AnyObject?
if url?.getResourceValue(&modified, forKey:NSURLAttributeModificationDateKey, error:nil) != nil {
printModDate = modified as? NSDate
} else {
printModDate = nil printModDate = nil
if let url = fileURL?.URLByDeletingLastPathComponent?.URLByAppendingPathComponent(logNode.path) {
do {
var modified : AnyObject?
try url.getResourceValue(&modified, forKey:NSURLAttributeModificationDateKey)
printModDate = modified as? NSDate
} catch (_) {
}
} }
} else { } else {
printModDate = mainEditor?.modDate() printModDate = mainEditor?.modDate()
@ -329,7 +329,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
} }
func printInformation() -> NSPrintInfo! { func printInformation() -> NSPrintInfo! {
var info = printInfo.copy() as! NSPrintInfo let info = printInfo.copy() as! NSPrintInfo
// //
// Minimize margins // Minimize margins
@ -358,9 +358,13 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
} }
func startPrintOperation(printOp: NSPrintOperation) { func startPrintOperation(printOp: NSPrintOperation) {
printOp.jobTitle = mainEditor?.name ?? if let editorName = mainEditor?.name {
fileURL?.lastPathComponent?.stringByDeletingPathExtension ?? printOp.jobTitle = editorName
"Untitled" } else if let fileName = fileURL?.lastPathComponent {
printOp.jobTitle = (fileName as NSString).stringByDeletingLastPathComponent
} else {
printOp.jobTitle = "Untitled"
}
printOp.showsPrintPanel = printShowPanel printOp.showsPrintPanel = printShowPanel
} }
@ -414,10 +418,11 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
if let fileNameStr = mainEditor?.name { if let fileNameStr = mainEditor?.name {
fileNameStr.drawAtPoint(titleAt, withAttributes:titleAttr) fileNameStr.drawAtPoint(titleAt, withAttributes:titleAttr)
} }
if let projectNameStr = fileURL?.lastPathComponent?.stringByDeletingPathExtension { if let projectNameStr = fileURL?.lastPathComponent {
let projectNameSize = projectNameStr.sizeWithAttributes(titleAttr) let projectNameTrimmed = (projectNameStr as NSString).stringByDeletingPathExtension
let projectNameSize = projectNameTrimmed.sizeWithAttributes(titleAttr)
titleAt.x = wideBox.origin.x+wideBox.size.width-projectNameSize.width-kXOffset titleAt.x = wideBox.origin.x+wideBox.size.width-projectNameSize.width-kXOffset
projectNameStr.drawAtPoint(titleAt, withAttributes:titleAttr) projectNameTrimmed.drawAtPoint(titleAt, withAttributes:titleAttr)
} }
} }
@ -494,7 +499,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
// MARK: File manipulation // MARK: File manipulation
@IBAction func delete(AnyObject) { @IBAction func delete(_: AnyObject) {
let selection = selectedFiles() let selection = selectedFiles()
var name : String var name : String
var ref : String var ref : String
@ -511,8 +516,8 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
alert.addButtonWithTitle("Move to Trash") alert.addButtonWithTitle("Move to Trash")
alert.addButtonWithTitle(selection.count == 1 ? "Remove Reference" : "Remove References") alert.addButtonWithTitle(selection.count == 1 ? "Remove Reference" : "Remove References")
alert.addButtonWithTitle("Cancel") alert.addButtonWithTitle("Cancel")
(alert.buttons[0] as! NSButton).keyEquivalent = "" alert.buttons[0].keyEquivalent = ""
(alert.buttons[1] as! NSButton).keyEquivalent = "\r" alert.buttons[1].keyEquivalent = "\r"
alert.beginSheetModalForWindow(outline.window!) { (response) in alert.beginSheetModalForWindow(outline.window!) { (response) in
if response != NSAlertThirdButtonReturn { if response != NSAlertThirdButtonReturn {
if response == NSAlertFirstButtonReturn { if response == NSAlertFirstButtonReturn {
@ -521,7 +526,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
self.files.apply { (node) in self.files.apply { (node) in
if let group = node as? ASFileGroup { if let group = node as? ASFileGroup {
for file in selection { for file in selection {
for (groupIdx, groupItem) in enumerate(group.children) { for (groupIdx, groupItem) in group.children.enumerate() {
if file as ASFileNode === groupItem { if file as ASFileNode === groupItem {
group.children.removeAtIndex(groupIdx) group.children.removeAtIndex(groupIdx)
break break
@ -537,7 +542,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
} }
} }
@IBAction func add(AnyObject) { @IBAction func add(_: AnyObject) {
let panel = NSOpenPanel() let panel = NSOpenPanel()
panel.canChooseFiles = true panel.canChooseFiles = true
panel.canChooseDirectories = false panel.canChooseDirectories = false
@ -546,7 +551,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
panel.delegate = self panel.delegate = self
panel.beginSheetModalForWindow(outline.window!, completionHandler: { (returnCode: Int) -> Void in panel.beginSheetModalForWindow(outline.window!, completionHandler: { (returnCode: Int) -> Void in
if returnCode == NSFileHandlingPanelOKButton { if returnCode == NSFileHandlingPanelOKButton {
for url in panel.URLs as! [NSURL] { for url in panel.URLs {
self.files.addFileURL(url) self.files.addFileURL(url)
} }
self.outline.deselectAll(self) self.outline.deselectAll(self)
@ -560,16 +565,19 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
func panel(panel:AnyObject, shouldEnableURL url:NSURL) -> Bool { func panel(panel:AnyObject, shouldEnableURL url:NSURL) -> Bool {
var shouldEnable = true var shouldEnable = true
var resourceID : AnyObject? var resourceID : AnyObject?
url.getResourceValue(&resourceID, forKey:NSURLFileResourceIdentifierKey, error:nil) guard ((try? url.getResourceValue(&resourceID, forKey:NSURLFileResourceIdentifierKey)) != nil) else {
return true;
}
files.apply {(node) in files.apply {(node) in
if let file = node as? ASFileItem { if let file = node as? ASFileItem {
var thisID : AnyObject? var thisID : AnyObject?
file.url.getResourceValue(&thisID, forKey:NSURLFileResourceIdentifierKey, error:nil) if (try? file.url.getResourceValue(&thisID, forKey:NSURLFileResourceIdentifierKey)) != nil {
if thisID != nil && resourceID!.isEqual(thisID!) { if thisID != nil && resourceID!.isEqual(thisID!) {
shouldEnable = false shouldEnable = false
} }
} }
} }
}
return shouldEnable return shouldEnable
} }
@ -614,15 +622,18 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
prefix + " Created: " + dateFmt.stringFromDate(NSDate()) + "\n" + prefix + " Created: " + dateFmt.stringFromDate(NSDate()) + "\n" +
lastPfx + "\n\n" lastPfx + "\n\n"
} }
header.writeToURL(url, atomically: true, encoding: NSUTF8StringEncoding, error: nil) do {
try header.writeToURL(url, atomically: true, encoding: NSUTF8StringEncoding)
} catch _ {
}
files.addFileURL(url) files.addFileURL(url)
outline.reloadData() outline.reloadData()
} }
@IBAction func createFile(AnyObject) { @IBAction func createFile(_: AnyObject) {
let savePanel = NSSavePanel() let savePanel = NSSavePanel()
savePanel.allowedFileTypes = savePanel.allowedFileTypes =
[kUTTypeCSource, kUTTypeCHeader, kUTTypeCPlusPlusSource, kUTTypeCSource, [kUTTypeCSource as String, kUTTypeCHeader as String, kUTTypeCPlusPlusSource as String, kUTTypeAssemblyLanguageSource as String,
"public.assembly-source", "net.daringfireball.markdown"] "public.assembly-source", "net.daringfireball.markdown"]
savePanel.beginSheetModalForWindow(outline.window!, completionHandler: { (returnCode) -> Void in savePanel.beginSheetModalForWindow(outline.window!, completionHandler: { (returnCode) -> Void in
if returnCode == NSFileHandlingPanelOKButton { if returnCode == NSFileHandlingPanelOKButton {
@ -634,14 +645,16 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
func importLibrary(lib: String) { func importLibrary(lib: String) {
var includes = "" var includes = ""
let fileManager = NSFileManager.defaultManager() let fileManager = NSFileManager.defaultManager()
for file in fileManager.contentsOfDirectoryAtPath(lib, error: nil) as! [String] { if let files = try? fileManager.contentsOfDirectoryAtPath(lib) {
for file in files {
if file.hasSuffix(".h") { if file.hasSuffix(".h") {
includes += "#include <\(file)>\n" includes += "#include <\(file)>\n"
} }
} }
var text = editor.string() as NSString }
let text = editor.string() as NSString
var insert = NSMakeRange(text.length, 0) var insert = NSMakeRange(text.length, 0)
let postHeaderComments = NSRegularExpression(pattern: "((?:\\s+|/\\*.*?\\*/|//.*?\\n)*)(.*?\\n)", options: .DotMatchesLineSeparators, error: nil)! let postHeaderComments = try! NSRegularExpression(pattern: "((?:\\s+|/\\*.*?\\*/|//.*?\\n)*)(.*?\\n)", options: .DotMatchesLineSeparators)
if let match = postHeaderComments.firstMatchInString(text as String, options:.Anchored, range:NSMakeRange(0, text.length)) { if let match = postHeaderComments.firstMatchInString(text as String, options:.Anchored, range:NSMakeRange(0, text.length)) {
let range = match.rangeAtIndex(2) let range = match.rangeAtIndex(2)
insert.location = range.location insert.location = range.location
@ -691,12 +704,12 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
return super.validateUserInterfaceItem(anItem) return super.validateUserInterfaceItem(anItem)
} }
@IBAction func makeTextLarger(AnyObject) { @IBAction func makeTextLarger(_: AnyObject) {
fontSize += 1 fontSize += 1
editor.setFontSize(fontSize) editor.setFontSize(fontSize)
updateChangeCount(.ChangeDone) updateChangeCount(.ChangeDone)
} }
@IBAction func makeTextSmaller(AnyObject) { @IBAction func makeTextSmaller(_: AnyObject) {
if fontSize > 6 { if fontSize > 6 {
fontSize -= 1 fontSize -= 1
editor.setFontSize(fontSize) editor.setFontSize(fontSize)
@ -715,44 +728,47 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
return return
} }
var enc : UInt = 0 var enc : UInt = 0
auxEdit.setString(NSString(contentsOfURL:url!, usedEncoding:&enc, error:nil) as? String ?? "") let contents = try? NSString(contentsOfURL:url!, usedEncoding:&enc)
auxEdit.setString(contents as? String ?? "")
editor.setMode(.Text) editor.setMode(.Text)
editor.alphaValue = 1.0 editor.alphaValue = 1.0
} }
let buildLog = auxEdit.string().componentsSeparatedByString("\n") let buildLog = auxEdit.string().componentsSeparatedByString("\n")
let issueRe = NSRegularExpression(pattern: "(\\S+?):(\\d+):.*", options: nil, error: nil)! let issueRe = try! NSRegularExpression(pattern: "(\\S+?):(\\d+):.*", options: [])
currentIssueLine += direction currentIssueLine += direction
while currentIssueLine > -1 && currentIssueLine < buildLog.count { while currentIssueLine > -1 && currentIssueLine < buildLog.count {
let line = buildLog[currentIssueLine] let line = buildLog[currentIssueLine]
let range = NSMakeRange(0, count(line.utf16)) let range = NSMakeRange(0, line.utf16.count)
if let match = issueRe.firstMatchInString(line, options:.Anchored, range:range) { if let match = issueRe.firstMatchInString(line, options:.Anchored, range:range) {
let file = match.rangeAtIndex(1) let file = match.rangeAtIndex(1)
let lineTxt = match.rangeAtIndex(2) let lineTxt = match.rangeAtIndex(2)
let nsline = line as NSString let nsline = line as NSString
let lineNo = nsline.substringWithRange(lineTxt).toInt()! let lineNo = Int(nsline.substringWithRange(lineTxt))!
let fileName = nsline.substringWithRange(file) as NSString let fileName = nsline.substringWithRange(file) as NSString
let fileURL : NSURL let fileURL : NSURL
if fileName.hasPrefix("../../") { if fileName.hasPrefix("../../") {
fileURL = files.dir.URLByAppendingPathComponent(fileName.substringFromIndex(6)) fileURL = files.dir.URLByAppendingPathComponent(fileName.substringFromIndex(6))
} else { } else {
fileURL = NSURL(fileURLWithPath:fileName as String)!.URLByStandardizingPath! fileURL = NSURL(fileURLWithPath:fileName as String).URLByStandardizingPath!
} }
jumpingToIssue = true jumpingToIssue = true
var resourceID : AnyObject? var resourceID : AnyObject?
fileURL.getResourceValue(&resourceID, forKey:NSURLFileResourceIdentifierKey, error:nil) if (try? fileURL.getResourceValue(&resourceID, forKey:NSURLFileResourceIdentifierKey)) != nil && resourceID != nil {
files.apply {(node) in files.apply {(node) in
if let file = node as? ASFileItem { if let file = node as? ASFileItem {
var thisID : AnyObject? var thisID : AnyObject?
file.url.getResourceValue(&thisID, forKey:NSURLFileResourceIdentifierKey, error:nil) if (try? file.url.getResourceValue(&thisID, forKey:NSURLFileResourceIdentifierKey)) != nil {
if thisID != nil && resourceID!.isEqual(thisID!) { if thisID != nil && resourceID!.isEqual(thisID!) {
self.selectNodeInOutline(node) self.selectNodeInOutline(node)
self.editor.gotoLine(lineNo, column:0, animated:true) self.editor.gotoLine(lineNo, column:0, animated:true)
} }
} }
} }
}
}
jumpingToIssue = false jumpingToIssue = false
auxEdit.gotoLine(currentIssueLine+1, column:0, animated: true) auxEdit.gotoLine(currentIssueLine+1, column:0, animated: true)
@ -764,12 +780,12 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
// MARK: Build / Upload // MARK: Build / Upload
@IBAction func buildProject(AnyObject) { @IBAction func buildProject(_: AnyObject) {
selectNodeInOutline(files.buildLog) selectNodeInOutline(files.buildLog)
builder.buildProject(board, files: files) builder.buildProject(board, files: files)
} }
@IBAction func cleanProject(AnyObject) { @IBAction func cleanProject(_: AnyObject) {
builder.cleanProject() builder.cleanProject()
selectNodeInOutline(files.buildLog) selectNodeInOutline(files.buildLog)
} }
@ -808,11 +824,11 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
if prop["name"] == newBoard { if prop["name"] == newBoard {
board = ident board = ident
pushToFront(&recentBoards, board) pushToFront(&recentBoards, front: board)
let userDefaults = NSUserDefaults.standardUserDefaults() let userDefaults = NSUserDefaults.standardUserDefaults()
var globalBoards = userDefaults.objectForKey(kRecentBoardsKey) as! [String] var globalBoards = userDefaults.objectForKey(kRecentBoardsKey) as! [String]
pushToFront(&globalBoards, board) pushToFront(&globalBoards, front: board)
userDefaults.setObject(globalBoards, forKey: kRecentBoardsKey) userDefaults.setObject(globalBoards, forKey: kRecentBoardsKey)
updateChangeCount(.ChangeDone) updateChangeCount(.ChangeDone)
@ -838,11 +854,11 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
if prop["name"] == newProg { if prop["name"] == newProg {
programmer = ident programmer = ident
pushToFront(&recentProgrammers, programmer) pushToFront(&recentProgrammers, front: programmer)
let userDefaults = NSUserDefaults.standardUserDefaults() let userDefaults = NSUserDefaults.standardUserDefaults()
var globalProgs = userDefaults.objectForKey(kRecentProgrammersKey) as! [String] var globalProgs = userDefaults.objectForKey(kRecentProgrammersKey) as! [String]
pushToFront(&globalProgs, programmer) pushToFront(&globalProgs, front: programmer)
userDefaults.setObject(globalProgs, forKey: kRecentProgrammersKey) userDefaults.setObject(globalProgs, forKey: kRecentProgrammersKey)
updateChangeCount(.ChangeDone) updateChangeCount(.ChangeDone)
@ -879,7 +895,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
var hasValidPort : Bool { var hasValidPort : Bool {
get { get {
return contains(ASSerial.ports() as! [String], port) return ASSerial.ports().contains(port)
} }
} }
class func keyPathsForValuesAffectingHasValidPort() -> NSSet { class func keyPathsForValuesAffectingHasValidPort() -> NSSet {

View File

@ -19,7 +19,7 @@ extern NSString * kASSerialPortsChanged;
@interface ASSerial : NSObject @interface ASSerial : NSObject
+ (NSString *) fileNameForPort:(NSString *)port; + (NSString *) fileNameForPort:(NSString *)port;
+ (NSArray *) ports; + (NSArray<NSString *> *) ports;
+ (NSFileHandle *)openPort:(NSString *) port withSpeed:(int)speed; + (NSFileHandle *)openPort:(NSString *) port withSpeed:(int)speed;
+ (void)restorePort:(int)fileDescriptor; + (void)restorePort:(int)fileDescriptor;
+ (void)closePort:(int)fileDescriptor; + (void)closePort:(int)fileDescriptor;

View File

@ -42,7 +42,7 @@ NSString * kASSerialPortsChanged = @"PortsChanged";
dispatch_resume(watchSlashDev); dispatch_resume(watchSlashDev);
} }
+ (NSArray *)ports { + (NSArray<NSString *> *)ports {
NSMutableArray * cuPorts = [NSMutableArray array]; NSMutableArray * cuPorts = [NSMutableArray array];
for (NSString * port in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/dev" error: nil]) { for (NSString * port in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/dev" error: nil]) {
if ([[port substringToIndex:2] isEqualToString:@"cu"]) if ([[port substringToIndex:2] isEqualToString:@"cu"])

View File

@ -103,7 +103,7 @@ class ASSerialWin: NSWindowController {
} }
} }
var nc = NSNotificationCenter.defaultCenter() let nc = NSNotificationCenter.defaultCenter()
serialObserver = nc.addObserverForName(kASSerialPortsChanged, object: nil, queue: nil, usingBlock: { (NSNotification) in serialObserver = nc.addObserverForName(kASSerialPortsChanged, object: nil, queue: nil, usingBlock: { (NSNotification) in
self.willChangeValueForKey("hasValidPort") self.willChangeValueForKey("hasValidPort")
self.didChangeValueForKey("hasValidPort") self.didChangeValueForKey("hasValidPort")
@ -118,7 +118,7 @@ class ASSerialWin: NSWindowController {
}) })
termination = NSNotificationCenter.defaultCenter().addObserverForName(NSTaskDidTerminateNotification, termination = NSNotificationCenter.defaultCenter().addObserverForName(NSTaskDidTerminateNotification,
object: nil, queue: nil, usingBlock: object: nil, queue: nil, usingBlock:
{ (notification: NSNotification!) in { (notification: NSNotification) in
if notification.object as? NSTask == self.task { if notification.object as? NSTask == self.task {
self.task = nil self.task = nil
self.portHandle = nil self.portHandle = nil
@ -174,7 +174,7 @@ class ASSerialWin: NSWindowController {
} }
} }
@IBAction func sendInput(AnyObject) { @IBAction func sendInput(_: AnyObject) {
let line = inputLine.stringValue + (sendCR ? "\r" : "") + (sendLF ? "\n" : "") let line = inputLine.stringValue + (sendCR ? "\r" : "") + (sendLF ? "\n" : "")
let data = line.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: true)! let data = line.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: true)!
portHandle?.writeData(data) portHandle?.writeData(data)
@ -191,7 +191,7 @@ class ASSerialWin: NSWindowController {
installReader((task.standardOutput as? NSPipe)?.fileHandleForReading) installReader((task.standardOutput as? NSPipe)?.fileHandleForReading)
} }
@IBAction func connect(AnyObject) { @IBAction func connect(_: AnyObject) {
shouldReconnect = false shouldReconnect = false
if task != nil { if task != nil {
task!.interrupt() task!.interrupt()
@ -227,7 +227,7 @@ class ASSerialWin: NSWindowController {
} }
var hasValidPort : Bool { var hasValidPort : Bool {
get { get {
return contains(ASSerial.ports() as! [String], port) return ASSerial.ports().contains(port)
} }
} }
@ -262,13 +262,13 @@ class ASSerialWin: NSWindowController {
return true return true
} }
@IBAction func makeTextLarger(AnyObject) { @IBAction func makeTextLarger(_: AnyObject) {
fontSize += 1 fontSize += 1
logView.setFontSize(fontSize) logView.setFontSize(fontSize)
portDefaults["FontSize"] = fontSize portDefaults["FontSize"] = fontSize
updatePortDefaults() updatePortDefaults()
} }
@IBAction func makeTextSmaller(AnyObject) { @IBAction func makeTextSmaller(_: AnyObject) {
if fontSize > 6 { if fontSize > 6 {
fontSize -= 1 fontSize -= 1
logView.setFontSize(fontSize) logView.setFontSize(fontSize)
@ -285,14 +285,17 @@ class ASSerialWin: NSWindowController {
userDefaults.setObject(serialDefaults, forKey:"SerialDefaults") userDefaults.setObject(serialDefaults, forKey:"SerialDefaults")
} }
@IBAction func saveDocument(AnyObject) { @IBAction func saveDocument(_: AnyObject) {
let savePanel = NSSavePanel() let savePanel = NSSavePanel()
savePanel.allowedFileTypes = ["log"] savePanel.allowedFileTypes = ["log"]
savePanel.allowsOtherFileTypes = true savePanel.allowsOtherFileTypes = true
savePanel.extensionHidden = false savePanel.extensionHidden = false
savePanel.beginSheetModalForWindow(window!, completionHandler: { (returnCode) -> Void in savePanel.beginSheetModalForWindow(window!, completionHandler: { (returnCode) -> Void in
if returnCode == NSFileHandlingPanelOKButton { if returnCode == NSFileHandlingPanelOKButton {
self.serialData.writeToURL(savePanel.URL!, atomically:false, encoding:NSUTF8StringEncoding, error:nil) do {
try self.serialData.writeToURL(savePanel.URL!, atomically:false, encoding:NSUTF8StringEncoding)
} catch _ {
}
} }
}) })
} }

View File

@ -18,13 +18,14 @@ class ASSketchBook {
class func findSketch(path: String) -> SketchBookItem { class func findSketch(path: String) -> SketchBookItem {
let fileManager = NSFileManager.defaultManager() let fileManager = NSFileManager.defaultManager()
var inoSketch = SketchBookItem.Nothing var inoSketch = SketchBookItem.Nothing
let contents = fileManager.contentsOfDirectoryAtPath(path, error: nil) as! [String] let contents = (try! fileManager.contentsOfDirectoryAtPath(path))
let nspath = path as NSString
for item in contents { for item in contents {
switch item.pathExtension { switch (item as NSString).pathExtension {
case "avrsackproj": case "avrsackproj":
return .Sketch(path.lastPathComponent, path.stringByAppendingPathComponent(item)) return .Sketch(nspath.lastPathComponent, nspath.stringByAppendingPathComponent(item))
case "ino": case "ino":
inoSketch = .Sketch(path.lastPathComponent, path.stringByAppendingPathComponent(item)) inoSketch = .Sketch(nspath.lastPathComponent, nspath.stringByAppendingPathComponent(item))
default: default:
break break
} }
@ -34,7 +35,8 @@ class ASSketchBook {
private class func enumerateSketches(path: String) -> SketchBookItem { private class func enumerateSketches(path: String) -> SketchBookItem {
let fileManager = NSFileManager.defaultManager() let fileManager = NSFileManager.defaultManager()
let contents = fileManager.contentsOfDirectoryAtPath(path, error: nil) as! [String] let contents = (try! fileManager.contentsOfDirectoryAtPath(path))
let nspath = path as NSString
let sketch = findSketch(path) let sketch = findSketch(path)
switch sketch { switch sketch {
case .Sketch: case .Sketch:
@ -44,7 +46,7 @@ class ASSketchBook {
} }
var sketches = [SketchBookItem]() var sketches = [SketchBookItem]()
for item in contents { for item in contents {
let subpath = path.stringByAppendingPathComponent(item) let subpath = nspath.stringByAppendingPathComponent(item)
var isDir : ObjCBool = false var isDir : ObjCBool = false
if fileManager.fileExistsAtPath(subpath, isDirectory: &isDir) && isDir { if fileManager.fileExistsAtPath(subpath, isDirectory: &isDir) && isDir {
let subEnum = enumerateSketches(subpath) let subEnum = enumerateSketches(subpath)
@ -56,7 +58,7 @@ class ASSketchBook {
} }
} }
} }
sketches.sort({ (a: SketchBookItem, b: SketchBookItem) -> Bool in sketches.sortInPlace({ (a: SketchBookItem, b: SketchBookItem) -> Bool in
var itemA : String = "" var itemA : String = ""
switch a { switch a {
case .Sketch(let item, _): case .Sketch(let item, _):
@ -75,7 +77,7 @@ class ASSketchBook {
return itemA < "" return itemA < ""
} }
}) })
return sketches.count > 0 ? .SketchDir(path.lastPathComponent, sketches) : .Nothing return sketches.count > 0 ? .SketchDir(nspath.lastPathComponent, sketches) : .Nothing
} }
class func appendSketchesToMenu(menu: NSMenu, target: AnyObject, action: Selector, sketchList: [SketchBookItem], inout sketches: [String]) { class func appendSketchesToMenu(menu: NSMenu, target: AnyObject, action: Selector, sketchList: [SketchBookItem], inout sketches: [String]) {
@ -100,7 +102,7 @@ class ASSketchBook {
class func addSketches(menu: NSMenu, target: AnyObject, action: Selector, path: String, inout sketches: [String]) { class func addSketches(menu: NSMenu, target: AnyObject, action: Selector, path: String, inout sketches: [String]) {
switch enumerateSketches(path) { switch enumerateSketches(path) {
case .SketchDir(let item, let sketchList): case .SketchDir(_, let sketchList):
appendSketchesToMenu(menu, target: target, action: action, sketchList: sketchList, sketches: &sketches) appendSketchesToMenu(menu, target: target, action: action, sketchList: sketchList, sketches: &sketches)
default: default:
break break