Compare commits
No commits in common. "7e17c0601c812db637639923440c6b530d3e0deb" and "58015d3e78ae1301a564221d53bbdda9c64a35e5" have entirely different histories.
7e17c0601c
...
58015d3e78
2
ACEView
2
ACEView
|
@ -1 +1 @@
|
||||||
Subproject commit 6928d3ce726e118924752cb8a636732b257e87cd
|
Subproject commit 36ad10e4a47110430f1d377571b4fd74cee05c21
|
|
@ -539,7 +539,7 @@
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = macosx10.13;
|
SDKROOT = macosx;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
|
@ -577,7 +577,7 @@
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = macosx10.13;
|
SDKROOT = macosx;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,17 +29,17 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
||||||
let workSpace = NSWorkspace.shared()
|
let workSpace = NSWorkspace.shared()
|
||||||
let userDefaults = UserDefaults.standard
|
let userDefaults = UserDefaults.standard
|
||||||
let appDefaultsURL = Bundle.main.url(forResource: "Defaults", withExtension: "plist")!
|
let appDefaultsURL = Bundle.main.url(forResource: "Defaults", withExtension: "plist")!
|
||||||
var appDefaults = NSDictionary(contentsOf: appDefaultsURL) as! [String: Any]
|
var appDefaults = NSDictionary(contentsOfURL: appDefaultsURL) as! [String: AnyObject]
|
||||||
//
|
//
|
||||||
// Add dynamic app defaults
|
// Add dynamic app defaults
|
||||||
//
|
//
|
||||||
if let arduinoPath = workSpace.urlForApplication(withBundleIdentifier: "cc.arduino.Arduino")?.path {
|
if let arduinoPath = workSpace.urlForApplication(withBundleIdentifier: "cc.arduino.Arduino")?.path {
|
||||||
appDefaults["Arduino"] = arduinoPath
|
appDefaults["Arduino"] = arduinoPath
|
||||||
}
|
}
|
||||||
var sketchbooks = [String]()
|
var sketchbooks = [NSString]()
|
||||||
for doc in fileManager.urls(for: .documentDirectory, in: .userDomainMask) {
|
for doc in fileManager.urls(for: .documentDirectory, in: .userDomainMask) {
|
||||||
sketchbooks.append(doc.appendingPathComponent("Arduino").path)
|
sketchbooks.append(doc.URLByAppendingPathComponent("Arduino").path!)
|
||||||
sketchbooks.append(doc.appendingPathComponent("AVRSack").path)
|
sketchbooks.append(doc.URLByAppendingPathComponent("AVRSack").path!)
|
||||||
}
|
}
|
||||||
appDefaults["Sketchbooks"] = sketchbooks
|
appDefaults["Sketchbooks"] = sketchbooks
|
||||||
if fileManager.fileExists(atPath: "/usr/local/CrossPack-AVR") {
|
if fileManager.fileExists(atPath: "/usr/local/CrossPack-AVR") {
|
||||||
|
@ -75,18 +75,16 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
||||||
sketches = [String]()
|
sketches = [String]()
|
||||||
for sketchBook in UserDefaults.standard.object(forKey:"Sketchbooks") as! [String] {
|
for sketchBook in UserDefaults.standard.object(forKey:"Sketchbooks") as! [String] {
|
||||||
if FileManager.default.fileExists(atPath: sketchBook) {
|
if FileManager.default.fileExists(atPath: sketchBook) {
|
||||||
ASSketchBook.addSketches(menu: menu, target: self, action: #selector(ASApplication.openSketch(_:)), path: sketchBook, sketches: &sketches)
|
ASSketchBook.addSketches(menu: menu, target: self, action: Selector(("openSketch:")), path: sketchBook, sketches: &sketches)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "Examples":
|
case "Examples":
|
||||||
menu.removeAllItems()
|
menu.removeAllItems()
|
||||||
examples = [String]()
|
examples = [String]()
|
||||||
if let arduinoURL = NSWorkspace.shared().urlForApplication(withBundleIdentifier: "cc.arduino.Arduino") {
|
if let arduinoURL = NSWorkspace.shared().urlForApplication(withBundleIdentifier: "cc.arduino.Arduino") {
|
||||||
let examplePath = arduinoURL.appendingPathComponent("Contents/Resources/Java/examples", isDirectory:true).path
|
let examplePath = arduinoURL.URLByAppendingPathComponent("Contents/Resources/Java/examples", isDirectory:true).path!
|
||||||
ASSketchBook.addSketches(menu: menu, target: self, action: #selector(ASApplication.openExample(_:)), path: examplePath, sketches: &examples)
|
ASSketchBook.addSketches(menu, target: self, action: "openExample:", path: examplePath, sketches: &examples)
|
||||||
}
|
}
|
||||||
ASLibraries.instance().addContribLibraryExamplesToMenu(menu: menu, sketches: &examples)
|
|
||||||
ASLibraries.instance().addStandardLibraryExamplesToMenu(menu: menu, sketches: &examples)
|
|
||||||
case "Import Standard Library":
|
case "Import Standard Library":
|
||||||
menu.removeAllItems()
|
menu.removeAllItems()
|
||||||
ASLibraries.instance().addStandardLibrariesToMenu(menu: menu)
|
ASLibraries.instance().addStandardLibrariesToMenu(menu: menu)
|
||||||
|
@ -99,18 +97,18 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
||||||
menu.removeItem(at: 2)
|
menu.removeItem(at: 2)
|
||||||
}
|
}
|
||||||
for port in ASSerial.ports() {
|
for port in ASSerial.ports() {
|
||||||
menu.addItem(withTitle: port, action:#selector(ASApplication.serialConnectMenu(_:)), keyEquivalent:"")
|
menu.addItem(withTitle: port, action:Selector(("serialConnectMenu:")), keyEquivalent:"")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func serialConnectMenu(_ port: NSMenuItem) {
|
@IBAction func serialConnectMenu(port: NSMenuItem) {
|
||||||
ASSerialWin.showWindowWithPort(port: port.title)
|
ASSerialWin.showWindowWithPort(port: port.title)
|
||||||
}
|
}
|
||||||
|
|
||||||
func openTemplate(template: URL, fromReadOnly: Bool) {
|
func openTemplate(template: NSURL, fromReadOnly: Bool) {
|
||||||
let editable : String
|
let editable : String
|
||||||
if fromReadOnly {
|
if fromReadOnly {
|
||||||
editable = "editable "
|
editable = "editable "
|
||||||
|
@ -118,31 +116,31 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
||||||
editable = ""
|
editable = ""
|
||||||
}
|
}
|
||||||
ASApplication.newProjectLocation(documentWindow: nil,
|
ASApplication.newProjectLocation(documentWindow: nil,
|
||||||
message: "Save \(editable)copy of project \(template.lastPathComponent)")
|
message: "Save \(editable)copy of project \(template.lastPathComponent!)")
|
||||||
{ (saveTo) -> Void in
|
{ (saveTo) -> Void in
|
||||||
let oldName = template.lastPathComponent
|
let oldName = template.lastPathComponent!
|
||||||
let newName = saveTo.lastPathComponent
|
let newName = saveTo.lastPathComponent!
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
do {
|
do {
|
||||||
try fileManager.copyItem(at: template, to: saveTo)
|
try fileManager.copyItemAtURL(template, toURL: saveTo)
|
||||||
let contents = fileManager.enumerator(at: saveTo,
|
let contents = fileManager.enumeratorAtURL(saveTo,
|
||||||
includingPropertiesForKeys: [URLResourceKey.nameKey, URLResourceKey.pathKey],
|
includingPropertiesForKeys: [URLResourceKey.nameKey, URLResourceKey.pathKey],
|
||||||
options: .skipsHiddenFiles, errorHandler: nil)
|
options: .SkipsHiddenFiles, errorHandler: nil)
|
||||||
while let item = contents?.nextObject() as? URL {
|
while let item = contents?.nextObject() as? NSURL {
|
||||||
let itemBase = item.deletingPathExtension().lastPathComponent
|
let itemBase = item.URLByDeletingPathExtension?.lastPathComponent!
|
||||||
if itemBase == oldName {
|
if itemBase == oldName {
|
||||||
let newItem = item.deletingLastPathComponent().appendingPathComponent(
|
let newItem = item.URLByDeletingLastPathComponent!.URLByAppendingPathComponent(
|
||||||
newName).appendingPathExtension(item.pathExtension)
|
newName).URLByAppendingPathExtension(item.pathExtension!)
|
||||||
try fileManager.moveItem(at: item, to: newItem)
|
try fileManager.moveItemAtURL(item, toURL: newItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
}
|
}
|
||||||
let sketch = ASSketchBook.findSketch(path: saveTo.path)
|
let sketch = ASSketchBook.findSketch(path: saveTo.path!)
|
||||||
switch sketch {
|
switch sketch {
|
||||||
case .Sketch(_, let path):
|
case .Sketch(_, let path):
|
||||||
let doc = NSDocumentController.shared()
|
let doc = NSDocumentController.shared()
|
||||||
doc.openDocument(withContentsOf: URL(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
|
||||||
|
@ -150,14 +148,14 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func openSketch(_ item: NSMenuItem) {
|
@IBAction func openSketch(item: NSMenuItem) {
|
||||||
let url = URL(fileURLWithPath: sketches[item.tag])
|
let url = NSURL(fileURLWithPath: sketches[item.tag])
|
||||||
let doc = NSDocumentController.shared()
|
let doc = NSDocumentController.shared()
|
||||||
doc.openDocument(withContentsOf: 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) {
|
||||||
let url = NSURL(fileURLWithPath: examples[item.tag])
|
let url = NSURL(fileURLWithPath: examples[item.tag])
|
||||||
openTemplate(template: url.deletingLastPathComponent!, fromReadOnly:true)
|
openTemplate(template: url.deletingLastPathComponent!, fromReadOnly:true)
|
||||||
}
|
}
|
||||||
|
@ -166,23 +164,23 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
||||||
ASApplication.newProjectLocation(documentWindow: nil,
|
ASApplication.newProjectLocation(documentWindow: nil,
|
||||||
message: "Create Project")
|
message: "Create Project")
|
||||||
{ (saveTo) -> Void in
|
{ (saveTo) -> Void in
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.defaultManager()
|
||||||
do {
|
do {
|
||||||
try fileManager.createDirectory(at: saveTo, withIntermediateDirectories:false, attributes:nil)
|
try fileManager.createDirectoryAtURL(saveTo, withIntermediateDirectories:false, attributes:nil)
|
||||||
let proj = saveTo.appendingPathComponent(saveTo.lastPathComponent+".avrsackproj")
|
let proj = saveTo.appendingPathComponent(saveTo.lastPathComponent!+".avrsackproj")
|
||||||
let docController = NSDocumentController.shared()
|
let docController = NSDocumentController.shared()
|
||||||
if let doc = try docController.openUntitledDocumentAndDisplay(true) as? ASProjDoc {
|
if let doc = try docController.openUntitledDocumentAndDisplay(true) as? ASProjDoc {
|
||||||
doc.fileURL = proj
|
doc.fileURL = proj
|
||||||
doc.updateProjectURL()
|
doc.updateProjectURL()
|
||||||
doc.createFileAtURL(url: saveTo.appendingPathComponent(saveTo.lastPathComponent+".ino"))
|
doc.createFileAtURL(url: saveTo.URLByAppendingPathComponent(saveTo.lastPathComponent!+".ino"))
|
||||||
try doc.write(to: proj, ofType: "Project", for: .saveAsOperation, originalContentsURL: nil)
|
try doc.writeToURL(proj, ofType: "Project", forSaveOperation: .SaveAsOperation, originalContentsURL: nil)
|
||||||
}
|
}
|
||||||
} catch _ {
|
} catch _ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class func newProjectLocation(documentWindow: NSWindow?, message: String, completion: @escaping (URL) -> ()) {
|
class func newProjectLocation(documentWindow: NSWindow?, message: String, completion: (NSURL) -> ()) {
|
||||||
let savePanel = NSSavePanel()
|
let savePanel = NSSavePanel()
|
||||||
savePanel.allowedFileTypes = [kUTTypeFolder as String]
|
savePanel.allowedFileTypes = [kUTTypeFolder as String]
|
||||||
savePanel.message = message
|
savePanel.message = message
|
||||||
|
@ -201,19 +199,19 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func goToHelpPage(_ sender: AnyObject) {
|
@IBAction func goToHelpPage(sender: AnyObject) {
|
||||||
let helpString: CFString
|
let helpString: String
|
||||||
switch sender.tag {
|
switch sender.tag {
|
||||||
case 0:
|
case 0:
|
||||||
helpString = "license.html" as CFString
|
helpString = "license.html"
|
||||||
default:
|
default:
|
||||||
abort()
|
abort()
|
||||||
}
|
}
|
||||||
let locBookName = Bundle.main.object(forInfoDictionaryKey: "CFBundleHelpBookName") as! CFString
|
let locBookName = Bundle.main.object(forInfoDictionaryKey: "CFBundleHelpBookName") as! String
|
||||||
AHGotoPage(locBookName, helpString, nil)
|
AHGotoPage(locBookName, helpString, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func goToHelpURL(_ sender: AnyObject) {
|
@IBAction func goToHelpURL(sender: AnyObject) {
|
||||||
let helpString: String
|
let helpString: String
|
||||||
switch sender.tag {
|
switch sender.tag {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -221,7 +219,7 @@ class ASApplication: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
||||||
default:
|
default:
|
||||||
abort()
|
abort()
|
||||||
}
|
}
|
||||||
NSWorkspace.shared().open(URL(string: helpString)!)
|
NSWorkspace.sharedWorkspace().openURL(NSURL(string: helpString)!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,16 +9,16 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class ASBuilder {
|
class ASBuilder {
|
||||||
var dir = URL(fileURLWithPath: "/")
|
var dir = NSURL()
|
||||||
var task : Process?
|
var task : Task?
|
||||||
var continuation: (()->())?
|
var continuation: (()->())?
|
||||||
var termination : AnyObject?
|
var termination : AnyObject?
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
termination = NotificationCenter.default.addObserver(forName: Process.didTerminateNotification,
|
termination = NotificationCenter.default.addObserver(forName: Task.didTerminateNotification,
|
||||||
object: nil, queue: nil, using:
|
object: nil, queue: nil, using:
|
||||||
{ (notification: Notification) in
|
{ (notification: Notification) in
|
||||||
if notification.object as? Process == self.task {
|
if notification.object as? Task == self.task {
|
||||||
if self.task!.terminationStatus == 0 {
|
if self.task!.terminationStatus == 0 {
|
||||||
if let cont = self.continuation {
|
if let cont = self.continuation {
|
||||||
self.continuation = nil
|
self.continuation = nil
|
||||||
|
@ -34,8 +34,8 @@ class ASBuilder {
|
||||||
NotificationCenter.default.removeObserver(termination!)
|
NotificationCenter.default.removeObserver(termination!)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setProjectURL(url: URL) {
|
func setProjectURL(url: NSURL) {
|
||||||
dir = url.deletingLastPathComponent().standardizedFileURL
|
dir = url.URLByDeletingLastPathComponent!.URLByStandardizingPath!
|
||||||
}
|
}
|
||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
|
@ -45,15 +45,15 @@ class ASBuilder {
|
||||||
|
|
||||||
func cleanProject() {
|
func cleanProject() {
|
||||||
do {
|
do {
|
||||||
try FileManager.default.removeItem(at: dir.appendingPathComponent("build"))
|
try FileManager.default.removeItem(at: dir.appendingPathComponent("build")!)
|
||||||
} catch _ {
|
} catch _ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildProject(board: String, files: ASFileTree) {
|
func buildProject(board: String, files: ASFileTree) {
|
||||||
let toolChain = (NSApplication.shared().delegate as! ASApplication).preferences.toolchainPath
|
let toolChain = (NSApplication.shared().delegate as! ASApplication).preferences.toolchainPath
|
||||||
task = Process()
|
task = Task()
|
||||||
task!.currentDirectoryPath = dir.path
|
task!.currentDirectoryPath = dir.path!
|
||||||
task!.launchPath = Bundle.main.path(forResource: "BuildProject", ofType: "")!
|
task!.launchPath = Bundle.main.path(forResource: "BuildProject", ofType: "")!
|
||||||
|
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
|
@ -81,7 +81,7 @@ class ASBuilder {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
args.append("toolchain="+toolChain)
|
args.append("toolchain="+toolChain)
|
||||||
args.append("project="+dir.lastPathComponent)
|
args.append("project="+dir.lastPathComponent!)
|
||||||
args.append("board="+board)
|
args.append("board="+board)
|
||||||
args.append("mcu="+boardProp["build.mcu"]!)
|
args.append("mcu="+boardProp["build.mcu"]!)
|
||||||
args.append("f_cpu="+boardProp["build.f_cpu"]!)
|
args.append("f_cpu="+boardProp["build.f_cpu"]!)
|
||||||
|
@ -111,8 +111,8 @@ class ASBuilder {
|
||||||
let interactive = mode == .Interactive
|
let interactive = mode == .Interactive
|
||||||
let portPath = ASSerial.fileName(forPort: port)
|
let portPath = ASSerial.fileName(forPort: port)
|
||||||
let toolChain = (NSApplication.shared().delegate as! ASApplication).preferences.toolchainPath
|
let toolChain = (NSApplication.shared().delegate as! ASApplication).preferences.toolchainPath
|
||||||
task = Process()
|
task = Task()
|
||||||
task!.currentDirectoryPath = dir.path
|
task!.currentDirectoryPath = dir.path!
|
||||||
task!.launchPath = toolChain+"/bin/avrdude"
|
task!.launchPath = toolChain+"/bin/avrdude"
|
||||||
|
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
|
@ -127,8 +127,8 @@ class ASBuilder {
|
||||||
} else {
|
} else {
|
||||||
ASSerialWin.portNeededForUpload(port: port)
|
ASSerialWin.portNeededForUpload(port: port)
|
||||||
let logURL = dir.appendingPathComponent("build/upload.log")
|
let logURL = dir.appendingPathComponent("build/upload.log")
|
||||||
fileManager.createFile(atPath: logURL.path, contents: Data(), attributes: nil)
|
fileManager.createFileAtPath(logURL.path, contents: NSData(), attributes: nil)
|
||||||
logOut = FileHandle(forWritingAtPath: logURL.path)!
|
logOut = FileHandle(forWritingAtPath: logURL.path!)!
|
||||||
task!.standardOutput = logOut
|
task!.standardOutput = logOut
|
||||||
task!.standardError = logOut
|
task!.standardError = logOut
|
||||||
}
|
}
|
||||||
|
@ -147,16 +147,16 @@ class ASBuilder {
|
||||||
var args = Array<String>(repeating: "-v", count: verbosity)
|
var args = Array<String>(repeating: "-v", count: verbosity)
|
||||||
args += [
|
args += [
|
||||||
"-C", toolChain+"/etc/avrdude.conf",
|
"-C", toolChain+"/etc/avrdude.conf",
|
||||||
"-p", boardProp["build.mcu"]!, "-c", proto!, "-P", portPath!]
|
"-p", boardProp["build.mcu"]!, "-c", proto!, "-P", portPath]
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Upload:
|
case .Upload:
|
||||||
if hasBootloader {
|
if hasBootloader {
|
||||||
args += ["-D"]
|
args += ["-D"]
|
||||||
}
|
}
|
||||||
args += ["-U", "flash:w:build/"+board+"/"+dir.lastPathComponent+".hex:i"]
|
args += ["-U", "flash:w:build/"+board+"/"+dir.lastPathComponent!+".hex:i"]
|
||||||
continuation = {
|
continuation = {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2*NSEC_PER_SEC)), dispatch_get_main_queue(), {
|
||||||
ASSerialWin.portAvailableAfterUpload(port: port)
|
ASSerialWin.portAvailableAfterUpload(port)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
case .BurnBootloader:
|
case .BurnBootloader:
|
||||||
|
@ -182,8 +182,8 @@ class ASBuilder {
|
||||||
needPhase2 = true
|
needPhase2 = true
|
||||||
}
|
}
|
||||||
if needPhase2 {
|
if needPhase2 {
|
||||||
let task2 = Process()
|
let task2 = Task()
|
||||||
task2.currentDirectoryPath = dir.path
|
task2.currentDirectoryPath = dir.path!
|
||||||
task2.launchPath = toolChain+"/bin/avrdude"
|
task2.launchPath = toolChain+"/bin/avrdude"
|
||||||
task2.arguments = loaderArgs
|
task2.arguments = loaderArgs
|
||||||
task2.standardOutput = logOut
|
task2.standardOutput = logOut
|
||||||
|
@ -193,8 +193,8 @@ class ASBuilder {
|
||||||
logOut.write(cmdLine.data(using: String.Encoding.utf8, allowLossyConversion: true)!)
|
logOut.write(cmdLine.data(using: String.Encoding.utf8, allowLossyConversion: true)!)
|
||||||
task2.launch()
|
task2.launch()
|
||||||
self.continuation = {
|
self.continuation = {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2*NSEC_PER_SEC)), dispatch_get_main_queue(), {
|
||||||
ASSerialWin.portAvailableAfterUpload(port: port)
|
ASSerialWin.portAvailableAfterUpload(port)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ class ASBuilder {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
for retry in 0 ..< 40 {
|
for retry in 0 ..< 40 {
|
||||||
usleep(250000)
|
usleep(250000)
|
||||||
if (fileManager.fileExists(atPath: portPath!)) {
|
if (fileManager.fileExistsAtPath(portPath)) {
|
||||||
if verbosity > 0 {
|
if verbosity > 0 {
|
||||||
logOut.write("Found port \(port) after \(retry) attempts.\n".data(using: String.Encoding.utf8, allowLossyConversion: true)!)
|
logOut.write("Found port \(port) after \(retry) attempts.\n".data(using: String.Encoding.utf8, allowLossyConversion: true)!)
|
||||||
}
|
}
|
||||||
|
@ -242,22 +242,22 @@ class ASBuilder {
|
||||||
|
|
||||||
func disassembleProject(board: String) {
|
func disassembleProject(board: String) {
|
||||||
let toolChain = (NSApplication.shared().delegate as! ASApplication).preferences.toolchainPath
|
let toolChain = (NSApplication.shared().delegate as! ASApplication).preferences.toolchainPath
|
||||||
task = Process()
|
task = Task()
|
||||||
task!.currentDirectoryPath = dir.path
|
task!.currentDirectoryPath = dir.path!
|
||||||
task!.launchPath = toolChain+"/bin/avr-objdump"
|
task!.launchPath = toolChain+"/bin/avr-objdump"
|
||||||
|
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
let logURL = dir.appendingPathComponent("build/disasm.log")
|
let logURL = dir.appendingPathComponent("build/disasm.log")
|
||||||
fileManager.createFile(atPath: logURL.path, contents: Data(), attributes: nil)
|
fileManager.createFileAtPath(logURL.path!, contents: NSData(), attributes: nil)
|
||||||
let logOut = FileHandle(forWritingAtPath: logURL.path)!
|
let logOut = FileHandle(forWritingAtPath: logURL.path!)!
|
||||||
task!.standardOutput = logOut
|
task!.standardOutput = logOut
|
||||||
task!.standardError = logOut
|
task!.standardError = logOut
|
||||||
|
|
||||||
let showSource = UserDefaults.standard.bool(forKey: "ShowSourceInDisassembly")
|
let showSource = UserDefaults.standard.bool(forKey: "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).componentsJoined(by: " ")+"\n"
|
let cmdLine = task!.launchPath!+" "+(args as NSArray).componentsJoined(by: " ")+"\n"
|
||||||
logOut.write(cmdLine.data(using: String.Encoding.utf8, allowLossyConversion: true)!)
|
logOut.writeData(cmdLine.dataUsingEncoding(String.Encoding.utf8, allowLossyConversion: true)!)
|
||||||
task!.arguments = args;
|
task!.arguments = args;
|
||||||
task!.launch()
|
task!.launch()
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ class ASFileNode : Equatable {
|
||||||
closure(self)
|
closure(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
func propertyList(rootPath: String) -> Dictionary<String, Any> {
|
func propertyList(rootPath: String) -> Dictionary<String, AnyObject> {
|
||||||
return [:]
|
return [:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ class ASFileGroup : ASFileNode {
|
||||||
|
|
||||||
private let kChildrenKey = "Children"
|
private let kChildrenKey = "Children"
|
||||||
private let kExpandedKey = "Expanded"
|
private let kExpandedKey = "Expanded"
|
||||||
fileprivate var kNodeType : String { return kNodeTypeGroup }
|
private var kNodeType : String { return kNodeTypeGroup }
|
||||||
|
|
||||||
override init(name: String = "") {
|
override init(name: String = "") {
|
||||||
self.children = []
|
self.children = []
|
||||||
|
@ -155,11 +155,11 @@ class ASFileGroup : ASFileNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func childrenPropertyList(rootPath: String) -> [Any] {
|
func childrenPropertyList(rootPath: String) -> [AnyObject] {
|
||||||
return children.map() { (node) in node.propertyList(rootPath: rootPath) }
|
return children.map() { (node) in node.propertyList(rootPath: rootPath) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override func propertyList(rootPath: String) -> Dictionary<String, Any> {
|
override func propertyList(rootPath: String) -> Dictionary<String, AnyObject> {
|
||||||
return [kTypeKey: kNodeType, kNameKey: name, kExpandedKey: expanded,
|
return [kTypeKey: kNodeType, kNameKey: name, kExpandedKey: expanded,
|
||||||
kChildrenKey: childrenPropertyList(rootPath: rootPath)]
|
kChildrenKey: childrenPropertyList(rootPath: rootPath)]
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ class ASFileGroup : ASFileNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ASProject : ASFileGroup {
|
class ASProject : ASFileGroup {
|
||||||
override fileprivate var kNodeType : String { return kNodeTypeProject }
|
override private var kNodeType : String { return kNodeTypeProject }
|
||||||
|
|
||||||
override init(name: String = "") {
|
override init(name: String = "") {
|
||||||
super.init(name: name)
|
super.init(name: name)
|
||||||
|
@ -211,13 +211,7 @@ class ASFileItem : ASFileNode {
|
||||||
} else {
|
} else {
|
||||||
url = URL(fileURLWithPath: path as String, relativeTo: rootURL).standardizedFileURL
|
url = URL(fileURLWithPath: path as String, relativeTo: rootURL).standardizedFileURL
|
||||||
}
|
}
|
||||||
var fileExists = false
|
if try! !url.checkResourceIsReachable() {
|
||||||
do {
|
|
||||||
fileExists = try url.checkResourceIsReachable()
|
|
||||||
} catch {
|
|
||||||
fileExists = false
|
|
||||||
}
|
|
||||||
if !fileExists {
|
|
||||||
//
|
//
|
||||||
// When projects get moved, .ino files get renamed but that fact is not
|
// When projects get moved, .ino files get renamed but that fact is not
|
||||||
// yet reflected in the project file.
|
// yet reflected in the project file.
|
||||||
|
@ -225,7 +219,7 @@ class ASFileItem : ASFileNode {
|
||||||
let urlDir = url.deletingLastPathComponent()
|
let urlDir = url.deletingLastPathComponent()
|
||||||
let newName = rootURL.appendingPathExtension(url.pathExtension).lastPathComponent
|
let newName = rootURL.appendingPathExtension(url.pathExtension).lastPathComponent
|
||||||
let altURL = urlDir.appendingPathComponent(newName)
|
let altURL = urlDir.appendingPathComponent(newName)
|
||||||
if let altExists = try? altURL.checkResourceIsReachable(), altExists {
|
if try! altURL.checkResourceIsReachable() {
|
||||||
url = altURL
|
url = altURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,7 +253,7 @@ class ASFileItem : ASFileNode {
|
||||||
return resComp.joined(separator: "/")
|
return resComp.joined(separator: "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
override func propertyList(rootPath: String) -> Dictionary<String, Any> {
|
override func propertyList(rootPath: String) -> Dictionary<String, AnyObject> {
|
||||||
return [kTypeKey: kNodeTypeFile, kKindKey: type.rawValue,
|
return [kTypeKey: kNodeTypeFile, kKindKey: type.rawValue,
|
||||||
kPathKey: relativePath(relativeTo: rootPath)]
|
kPathKey: relativePath(relativeTo: rootPath)]
|
||||||
}
|
}
|
||||||
|
@ -269,21 +263,17 @@ class ASFileItem : ASFileNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func exists() -> Bool {
|
override func exists() -> Bool {
|
||||||
do {
|
return try! url.checkResourceIsReachable()
|
||||||
return try url.checkResourceIsReachable()
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func modDate() -> Date? {
|
override func modDate() -> Date? {
|
||||||
let values = try? url.resourceValues(forKeys: [.contentModificationDateKey])
|
let values = try? url.resourceValues(forKeys: [URLResourceKey.contentModificationDateKey])
|
||||||
|
|
||||||
return values?.contentModificationDate
|
return values?.contentModificationDate
|
||||||
}
|
}
|
||||||
|
|
||||||
override func revision() -> String? {
|
override func revision() -> String? {
|
||||||
let task = Process()
|
let task = Task()
|
||||||
task.launchPath = Bundle.main.path(forResource: "FileRevision", ofType: "")!
|
task.launchPath = Bundle.main.path(forResource: "FileRevision", ofType: "")!
|
||||||
let outputPipe = Pipe()
|
let outputPipe = Pipe()
|
||||||
task.standardOutput = outputPipe
|
task.standardOutput = outputPipe
|
||||||
|
@ -319,7 +309,7 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
|
||||||
func apply(closure: (ASFileNode) -> ()) {
|
func apply(closure: (ASFileNode) -> ()) {
|
||||||
root.apply(closure: closure)
|
root.apply(closure: closure)
|
||||||
}
|
}
|
||||||
func propertyList() -> Any {
|
func propertyList() -> AnyObject {
|
||||||
return root.propertyList(rootPath: projectPath())
|
return root.propertyList(rootPath: projectPath())
|
||||||
}
|
}
|
||||||
func readPropertyList(prop: Dictionary<String, AnyObject>) {
|
func readPropertyList(prop: Dictionary<String, AnyObject>) {
|
||||||
|
@ -330,14 +320,14 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Outline Data Source
|
// MARK: Outline Data Source
|
||||||
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: AnyObject?) -> Int {
|
||||||
if item == nil {
|
if item == nil {
|
||||||
return 4
|
return 4
|
||||||
} else {
|
} else {
|
||||||
return (item as! ASFileGroup).children.count
|
return (item as! ASFileGroup).children.count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: AnyObject?) -> AnyObject {
|
||||||
if item == nil {
|
if item == nil {
|
||||||
switch index {
|
switch index {
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -354,15 +344,15 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
|
||||||
return group.children[index]
|
return group.children[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: AnyObject) -> Bool {
|
||||||
return item is ASFileGroup
|
return item is ASFileGroup
|
||||||
}
|
}
|
||||||
func outlineView(_ outlineView: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? {
|
func outlineView(_ outlineView: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: AnyObject?) -> AnyObject? {
|
||||||
return (item as! ASFileNode).nodeName()
|
return (item as! ASFileNode).nodeName()
|
||||||
}
|
}
|
||||||
|
|
||||||
let kLocalReorderPasteboardType = "ASFilePasteboardType"
|
let kLocalReorderPasteboardType = "ASFilePasteboardType"
|
||||||
private func outlineView(_ outlineView: NSOutlineView, writeItems items: [AnyObject], to pasteboard: NSPasteboard) -> Bool {
|
func outlineView(_ outlineView: NSOutlineView, writeItems items: [AnyObject], to pasteboard: NSPasteboard) -> Bool {
|
||||||
dragged = items as! [ASFileNode]
|
dragged = items as! [ASFileNode]
|
||||||
pasteboard.declareTypes([kLocalReorderPasteboardType], owner: self)
|
pasteboard.declareTypes([kLocalReorderPasteboardType], owner: self)
|
||||||
pasteboard.setData(Data(), forType: kLocalReorderPasteboardType)
|
pasteboard.setData(Data(), forType: kLocalReorderPasteboardType)
|
||||||
|
@ -378,7 +368,7 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
|
||||||
return itemIsDescendentOfDrag(outlineView: outlineView, item: outlineView.parent(forItem: item) as! ASFileNode)
|
return itemIsDescendentOfDrag(outlineView: outlineView, item: outlineView.parent(forItem: item) as! ASFileNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func outlineView(_ outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
|
func outlineView(_ outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: AnyObject?, proposedChildIndex index: Int) -> NSDragOperation {
|
||||||
if info.draggingPasteboard().availableType(from: [kLocalReorderPasteboardType]) == nil {
|
if info.draggingPasteboard().availableType(from: [kLocalReorderPasteboardType]) == nil {
|
||||||
return [] // Only allow reordering drags
|
return [] // Only allow reordering drags
|
||||||
}
|
}
|
||||||
|
@ -400,7 +390,7 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
|
||||||
}
|
}
|
||||||
return NSDragOperation.generic
|
return NSDragOperation.generic
|
||||||
}
|
}
|
||||||
func outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex insertAtIndex: Int) -> Bool {
|
func outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: AnyObject?, childIndex insertAtIndex: Int) -> Bool {
|
||||||
var insertAtIndex = insertAtIndex
|
var insertAtIndex = insertAtIndex
|
||||||
let parent : ASFileGroup = (item as? ASFileGroup) ?? root
|
let parent : ASFileGroup = (item as? ASFileGroup) ?? root
|
||||||
if insertAtIndex == NSOutlineViewDropOnItemIndex {
|
if insertAtIndex == NSOutlineViewDropOnItemIndex {
|
||||||
|
|
|
@ -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(by: { $0["name"]! < $1["name"]! }) {
|
for choice in choices.sorted(by: { $0["name"] < $1["name"] }) {
|
||||||
let item = self.addItem(withTitle: choice["name"]!, action: selector, keyEquivalent: "")
|
let item = self.addItem(withTitle: choice["name"]!, action: selector, keyEquivalent: "")
|
||||||
item.target = target
|
item.target = target
|
||||||
}
|
}
|
||||||
|
@ -189,31 +189,6 @@ class ASLibraries : NSObject {
|
||||||
menuItem.tag = index
|
menuItem.tag = index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func addStandardLibraryExamplesToMenu(menu: NSMenu, sketches: inout [String]) {
|
|
||||||
addLibraryExamplesToMenu(library: standardLib, menu: menu, sketches: &sketches)
|
|
||||||
}
|
|
||||||
func addContribLibraryExamplesToMenu(menu: NSMenu, sketches: inout [String]) {
|
|
||||||
addLibraryExamplesToMenu(library: contribLib, menu: menu, sketches: &sketches)
|
|
||||||
}
|
|
||||||
func addLibraryExamplesToMenu(library: [String], menu: NSMenu, sketches: inout [String]) {
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
let application = NSApplication.shared().delegate as! ASApplication
|
|
||||||
var hasSeparator = false
|
|
||||||
for (_,lib) in library.enumerated() {
|
|
||||||
let examplePath = (lib as NSString).appendingPathComponent("examples")
|
|
||||||
if fileManager.fileExists(atPath: examplePath) {
|
|
||||||
if !hasSeparator {
|
|
||||||
menu.addItem(NSMenuItem.separator())
|
|
||||||
hasSeparator = true
|
|
||||||
}
|
|
||||||
let menuItem = menu.addItem(withTitle: (lib as NSString).lastPathComponent, action: nil, keyEquivalent: "")
|
|
||||||
let submenu = NSMenu()
|
|
||||||
submenu.autoenablesItems = false
|
|
||||||
ASSketchBook.addSketches(menu: submenu, target: application, action: #selector(ASApplication.openExample(_:)), path: examplePath, sketches: &sketches)
|
|
||||||
menu.setSubmenu(submenu, for: menuItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@IBAction func importStandardLibrary(_ menuItem: AnyObject) {
|
@IBAction func importStandardLibrary(_ menuItem: AnyObject) {
|
||||||
if let tag = (menuItem as? NSMenuItem)?.tag {
|
if let tag = (menuItem as? NSMenuItem)?.tag {
|
||||||
NSApplication.shared().sendAction(#selector(ASProjDoc.importLibrary(_:)), to: nil, from: standardLib[tag])
|
NSApplication.shared().sendAction(#selector(ASProjDoc.importLibrary(_:)), to: nil, from: standardLib[tag])
|
||||||
|
|
|
@ -86,8 +86,8 @@ class ASPreferences: NSWindowController, NSOpenSavePanelDelegate {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func panel(_ sender: Any, shouldEnable url: URL) -> Bool {
|
func panel(_ sender: AnyObject, shouldEnable url: URL) -> Bool {
|
||||||
let gccPath = url.appendingPathComponent("bin/avr-gcc")
|
let gccPath = url.URLByAppendingPathComponent("bin/avr-gcc")
|
||||||
return FileManager.default.fileExists(atPath: gccPath.path)
|
return FileManager.defaultManager().fileExistsAtPath(gccPath.path!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,11 +48,11 @@ 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 = Date.distantPast
|
var logModified = NSDate.distantPast
|
||||||
var logSize = 0
|
var logSize = 0
|
||||||
var updateLogTimer : Timer?
|
var updateLogTimer : Timer?
|
||||||
var printingDone : () -> () = {}
|
var printingDone : () -> () = {}
|
||||||
var printModDate : Date?
|
var printModDate : NSDate?
|
||||||
var printRevision : String?
|
var printRevision : String?
|
||||||
var printShowPanel = false
|
var printShowPanel = false
|
||||||
var jumpingToIssue = false
|
var jumpingToIssue = false
|
||||||
|
@ -130,7 +130,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
outline.setDraggingSourceOperationMask(NSDragOperation.every, forLocal: true)
|
outline.setDraggingSourceOperationMask(NSDragOperation.every, forLocal: true)
|
||||||
outline.setDraggingSourceOperationMask([], forLocal: false)
|
outline.setDraggingSourceOperationMask([], forLocal: false)
|
||||||
|
|
||||||
outline.dataSource = files
|
outline.setDataSource(files)
|
||||||
files.apply() { node in
|
files.apply() { node in
|
||||||
if let group = node as? ASFileGroup {
|
if let group = node as? ASFileGroup {
|
||||||
if group.expanded {
|
if group.expanded {
|
||||||
|
@ -160,13 +160,13 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
func saveCurEditor() {
|
func saveCurEditor() {
|
||||||
if let file = (mainEditor as? ASFileItem) {
|
if let file = (mainEditor as? ASFileItem) {
|
||||||
do {
|
do {
|
||||||
try editor.string().write(to: file.url, atomically: true, encoding: String.Encoding.utf8)
|
try editor.string().writeToURL(file.url, atomically: true, encoding: String.Encoding.utf8)
|
||||||
} catch _ {
|
} catch _ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func data(ofType typeName: String) throws -> Data {
|
override func dataOfType(typeName: String) throws -> NSData {
|
||||||
let data = [kVersionKey: kCurVersion,
|
let data = [kVersionKey: kCurVersion,
|
||||||
kThemeKey: ACEThemeNames.name(for: currentTheme),
|
kThemeKey: ACEThemeNames.name(for: currentTheme),
|
||||||
kFontSizeKey: fontSize,
|
kFontSizeKey: fontSize,
|
||||||
|
@ -176,8 +176,8 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
kPortKey: port,
|
kPortKey: port,
|
||||||
kRecentBoardsKey: recentBoards,
|
kRecentBoardsKey: recentBoards,
|
||||||
kRecentProgrammersKey: recentProgrammers
|
kRecentProgrammersKey: recentProgrammers
|
||||||
] as [String : Any]
|
]
|
||||||
return try PropertyListSerialization.data(fromPropertyList: data, format:.xml, options:0)
|
return try PropertyListSerialization.dataWithPropertyList(data, format:.XMLFormat_v1_0, options:0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateProjectURL() {
|
func updateProjectURL() {
|
||||||
|
@ -185,44 +185,44 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
builder.setProjectURL(url: fileURL!)
|
builder.setProjectURL(url: fileURL!)
|
||||||
}
|
}
|
||||||
|
|
||||||
func importProject(url: URL) throws {
|
func importProject(url: NSURL) throws {
|
||||||
let existingProject = url.appendingPathComponent(url.lastPathComponent+".avrsackproj")
|
let existingProject = url.appendingPathComponent(url.lastPathComponent!+".avrsackproj")
|
||||||
if let hasProject = try? existingProject.checkResourceIsReachable(), hasProject {
|
if existingProject.checkResourceIsReachableAndReturnError(nil) {
|
||||||
fileURL = existingProject
|
fileURL = existingProject
|
||||||
try read(from: existingProject, ofType:"Project")
|
try readFromURL(url: existingProject, ofType:"Project")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let filesInProject =
|
let filesInProject =
|
||||||
(try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil,
|
(try FileManagerefaultManager().contentsOfDirectoryAtURL(url, includingPropertiesForKeys: nil,
|
||||||
options: .skipsHiddenFiles))
|
options: .SkipsHiddenFiles))
|
||||||
updateProjectURL()
|
updateProjectURL()
|
||||||
for file in filesInProject {
|
for file in filesInProject {
|
||||||
files.addFileURL(url: file)
|
files.addFileURL(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func read(from url: URL, ofType typeName: String) throws {
|
override func readFromURL(url: NSURL, ofType typeName: String) throws {
|
||||||
if typeName == "Arduino Source File" {
|
if typeName == "Arduino Source File" {
|
||||||
let projectURL = url.deletingPathExtension().appendingPathExtension("avrsackproj")
|
let projectURL = url.URLByDeletingPathExtension!.URLByAppendingPathExtension("avrsackproj")
|
||||||
try importProject(url: url.deletingLastPathComponent())
|
try importProject(url: url.deletingLastPathComponent!)
|
||||||
fileURL = projectURL
|
fileURL = projectURL
|
||||||
try write(to: projectURL, ofType: "Project", for: .saveAsOperation, originalContentsURL: nil)
|
try writeToURL(projectURL, ofType: "Project", forSaveOperation: .SaveAsOperation, originalContentsURL: nil)
|
||||||
} else {
|
} else {
|
||||||
fileURL = url
|
fileURL = url
|
||||||
try super.read(from: url, ofType: typeName)
|
try super.readFromURL(url, ofType: typeName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override func read(from data: Data, ofType typeName: String) throws {
|
override func readFromData(data: NSData, ofType typeName: String) throws {
|
||||||
if typeName != ("Project" as String) {
|
if typeName != ("Project" as String) {
|
||||||
throw NSError(domain: "AVRSack", code: 0, userInfo: nil)
|
throw NSError(domain: "AVRSack", code: 0, userInfo: nil)
|
||||||
}
|
}
|
||||||
updateProjectURL()
|
updateProjectURL()
|
||||||
let projectData =
|
let projectData =
|
||||||
(try PropertyListSerialization.propertyList(from: data, options:[], format:nil)) as! NSDictionary
|
(try PropertyListSerialization.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 {
|
||||||
if let themeId = ACEView.themeIdByName(themeName: themeName) {
|
if let themeId = ACEView.themeIdByName(themeName) {
|
||||||
currentTheme = themeId
|
currentTheme = themeId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,27 +238,34 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
updateChangeCount(.changeCleared)
|
updateChangeCount(.changeCleared)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func duplicate(_ sender: Any?) {
|
override func duplicate(_ sender: AnyObject?) {
|
||||||
let app = NSApplication.shared().delegate as! ASApplication
|
let app = NSApplication.shared().delegate as! ASApplication
|
||||||
app.openTemplate(template: fileURL!.deletingLastPathComponent(), fromReadOnly:false)
|
app.openTemplate(fileURL!.URLByDeletingLastPathComponent!, fromReadOnly:false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLog(_: AnyObject?) {
|
func updateLog(_: AnyObject?) {
|
||||||
if let logNode = mainEditor as? ASLogNode {
|
if let logNode = mainEditor as? ASLogNode {
|
||||||
guard let fileURL = fileURL else { return }
|
let url = fileURL?.URLByDeletingLastPathComponent?.URLByAppendingPathComponent(logNode.path)
|
||||||
let url = fileURL.deletingLastPathComponent().appendingPathComponent(logNode.path)
|
if url == nil {
|
||||||
if let values = try? url.resourceValues(forKeys: [.attributeModificationDateKey, .fileSizeKey]) {
|
return
|
||||||
if values.attributeModificationDate!.compare(logModified) == .orderedDescending
|
}
|
||||||
|| values.fileSize! != logSize
|
var modified : AnyObject?
|
||||||
{
|
var size : AnyObject?
|
||||||
var enc : String.Encoding = .utf8
|
do {
|
||||||
let newText = try? String(contentsOf: url, usedEncoding:&enc)
|
try url!.getResourceValue(&modified, forKey:NSURLAttributeModificationDateKey)
|
||||||
editor.setString(newText ?? "")
|
try url!.getResourceValue(&size, forKey:NSURLFileSizeKey)
|
||||||
editor.gotoLine(1000000000, column: 0, animated: true)
|
} catch (_) {
|
||||||
logModified = values.attributeModificationDate!
|
return
|
||||||
logSize = values.fileSize!
|
}
|
||||||
currentIssueLine = -1
|
|
||||||
}
|
if (modified as! NSDate).compare(logModified) == .orderedDescending || (size as! Int) != logSize {
|
||||||
|
var enc : UInt = 0
|
||||||
|
let newText = try? NSString(contentsOfURL:url!, usedEncoding:&enc)
|
||||||
|
editor.setString((newText as? String) ?? "")
|
||||||
|
editor.gotoLine(1000000000, column: 0, animated: true)
|
||||||
|
logModified = modified as! NSDate
|
||||||
|
logSize = size as! Int
|
||||||
|
currentIssueLine = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,9 +274,9 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
saveCurEditor()
|
saveCurEditor()
|
||||||
}
|
}
|
||||||
if let file = (selection as? ASFileItem) {
|
if let file = (selection as? ASFileItem) {
|
||||||
var enc : String.Encoding = .utf8
|
var enc : UInt = 0
|
||||||
let contents = try? String(contentsOf:file.url, usedEncoding:&enc)
|
let contents = try? NSString(contentsOfURL:file.url, usedEncoding:&enc)
|
||||||
editor.setString(contents ?? "")
|
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
|
||||||
|
@ -286,13 +293,13 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func selectNodeInOutline(selection: ASFileNode) {
|
func selectNodeInOutline(selection: ASFileNode) {
|
||||||
let selectedIndexes = IndexSet(integer: outline.row(forItem: selection))
|
let selectedIndexes = NSIndexSet(index: outline.row(forItem: selection))
|
||||||
outline.selectRowIndexes(selectedIndexes, byExtendingSelection: false)
|
outline.selectRowIndexes(selectedIndexes, byExtendingSelection: false)
|
||||||
}
|
}
|
||||||
func selectedFiles() -> [ASFileItem] {
|
func selectedFiles() -> [ASFileItem] {
|
||||||
var selection = [ASFileItem]()
|
var selection = [ASFileItem]()
|
||||||
for index in outline.selectedRowIndexes {
|
outline.selectedRowIndexes.enumerateIndexesUsingBlock() { (index, stop) in
|
||||||
if let file = self.outline.item(atRow: index) as? ASFileItem {
|
if let file = self.outline.itemAtRow(index) as? ASFileItem {
|
||||||
selection.append(file)
|
selection.append(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,20 +308,22 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
|
|
||||||
// MARK: Printing
|
// MARK: Printing
|
||||||
|
|
||||||
override func print(withSettings printSettings: [String : Any], showPrintPanel: Bool, delegate: Any?, didPrint didPrintSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) {
|
override func print(withSettings printSettings: [String : AnyObject], showPrintPanel: Bool, delegate: AnyObject?, didPrint didPrintSelector: Selector?, contextInfo: UnsafeMutablePointer<Void>) {
|
||||||
printingDone =
|
printingDone =
|
||||||
{ () -> () in
|
{ () -> () in
|
||||||
InvokeCallback(delegate, didPrintSelector, contextInfo);
|
InvokeCallback(delegate, didPrintSelector, contextInfo);
|
||||||
}
|
}
|
||||||
printModDate = nil
|
|
||||||
if let logNode = mainEditor as? ASLogNode {
|
if let logNode = mainEditor as? ASLogNode {
|
||||||
if let url = fileURL?.deletingLastPathComponent().appendingPathComponent(logNode.path),
|
printModDate = nil
|
||||||
let values = try? url.resourceValues(forKeys: [.attributeModificationDateKey])
|
if let url = fileURL?.URLByDeletingLastPathComponent?.URLByAppendingPathComponent(logNode.path) {
|
||||||
{
|
do {
|
||||||
printModDate = values.attributeModificationDate
|
var modified : AnyObject?
|
||||||
|
try url.getResourceValue(&modified, forKey:NSURLAttributeModificationDateKey)
|
||||||
|
printModDate = modified as? NSDate
|
||||||
|
} catch (_) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if printModDate == nil {
|
|
||||||
printModDate = mainEditor?.modDate()
|
printModDate = mainEditor?.modDate()
|
||||||
}
|
}
|
||||||
printRevision = mainEditor?.revision()
|
printRevision = mainEditor?.revision()
|
||||||
|
@ -395,7 +404,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
let pageNoAttr = [
|
let pageNoAttr = [
|
||||||
NSFontAttributeName: pageNoFont,
|
NSFontAttributeName: pageNoFont,
|
||||||
NSForegroundColorAttributeName: NSColor.white,
|
NSForegroundColorAttributeName: NSColor.white,
|
||||||
NSStrokeWidthAttributeName: -5.0] as [String : Any]
|
NSStrokeWidthAttributeName: -5.0]
|
||||||
let pageNoStr = "\(pageNo)"
|
let pageNoStr = "\(pageNo)"
|
||||||
let pageNoSize = pageNoStr.size(withAttributes: pageNoAttr)
|
let pageNoSize = pageNoStr.size(withAttributes: pageNoAttr)
|
||||||
let pageNoAt = NSPoint(
|
let pageNoAt = NSPoint(
|
||||||
|
@ -445,10 +454,10 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
{
|
{
|
||||||
let dateFormatter = DateFormatter()
|
let dateFormatter = DateFormatter()
|
||||||
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
|
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
|
||||||
let modDateStr = dateFormatter.string(from: modDate)
|
let modDateStr = dateFormatter.stringFromDate(modDate)
|
||||||
let modDateSize = modDateStr.size(withAttributes: footAttr)
|
let modDateSize = modDateStr.sizeWithAttributes(footAttr)
|
||||||
footAt.x = rect.origin.x+rect.size.width-modDateSize.width-kXOffset
|
footAt.x = rect.origin.x+rect.size.width-modDateSize.width-kXOffset
|
||||||
modDateStr.draw(at: footAt, withAttributes:footAttr)
|
modDateStr.drawAtPoint(footAt, withAttributes:footAttr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,20 +487,20 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
group.expanded = false
|
group.expanded = false
|
||||||
updateChangeCount(.changeDone)
|
updateChangeCount(.changeDone)
|
||||||
}
|
}
|
||||||
func outlineView(_ outlineView: NSOutlineView, willDisplayCell cell: Any, for tableColumn: NSTableColumn?, item: Any) {
|
func outlineView(_ outlineView: NSOutlineView, willDisplayCell cell: AnyObject, for tableColumn: NSTableColumn?, item: AnyObject) {
|
||||||
if let textCell = cell as? NSTextFieldCell, let item = item as? ASFileNode {
|
if let textCell = cell as? NSTextFieldCell {
|
||||||
textCell.textColor = NSColor.black
|
textCell.textColor = NSColor.blackColor
|
||||||
if item === files.root || item === files.buildLog || item === files.uploadLog || item === files.disassembly {
|
if item === files.root || item === files.buildLog || item === files.uploadLog || item === files.disassembly {
|
||||||
textCell.font = NSFont.boldSystemFont(ofSize: 13.0)
|
textCell.font = NSFont.boldSystemFont(ofSize: 13.0)
|
||||||
} else {
|
} else {
|
||||||
textCell.font = NSFont.systemFont(ofSize: 13.0)
|
textCell.font = NSFont.systemFont(ofSize: 13.0)
|
||||||
if !item.exists() {
|
if !(item as! ASFileNode).exists() {
|
||||||
textCell.textColor = NSColor.red
|
textCell.textColor = NSColor.redColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func outlineView(_ outlineView: NSOutlineView, shouldTrackCell cell: NSCell, for tableColumn: NSTableColumn?, item: Any) -> Bool {
|
func outlineView(_ outlineView: NSOutlineView, shouldTrackCell cell: NSCell, for tableColumn: NSTableColumn?, item: AnyObject) -> Bool {
|
||||||
return outlineView.isRowSelected(outlineView.row(forItem: item))
|
return outlineView.isRowSelected(outlineView.row(forItem: item))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,7 +510,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
var name : String
|
var name : String
|
||||||
var ref : String
|
var ref : String
|
||||||
if selection.count == 1 {
|
if selection.count == 1 {
|
||||||
name = "file “\(selection[0].url.lastPathComponent)”"
|
name = "file “\(selection[0].url.lastPathComponent!)”"
|
||||||
ref = "reference to it"
|
ref = "reference to it"
|
||||||
} else {
|
} else {
|
||||||
name = "\(selection.count) selected files"
|
name = "\(selection.count) selected files"
|
||||||
|
@ -518,7 +527,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
alert.beginSheetModal(for: outline.window!) { (response) in
|
alert.beginSheetModal(for: outline.window!) { (response) in
|
||||||
if response != NSAlertThirdButtonReturn {
|
if response != NSAlertThirdButtonReturn {
|
||||||
if response == NSAlertFirstButtonReturn {
|
if response == NSAlertFirstButtonReturn {
|
||||||
NSWorkspace.shared().recycle(selection.map {$0.url}, completionHandler:nil)
|
NSWorkspace.sharedWorkspace().recycleURLs(selection.map {$0.url}, completionHandler:nil)
|
||||||
}
|
}
|
||||||
self.files.apply { (node) in
|
self.files.apply { (node) in
|
||||||
if let group = node as? ASFileGroup {
|
if let group = node as? ASFileGroup {
|
||||||
|
@ -559,20 +568,19 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func panel(_ panel:Any, shouldEnable url:URL) -> Bool {
|
func panel(_ panel:AnyObject, shouldEnable url:URL) -> Bool {
|
||||||
guard let values = try? url.resourceValues(forKeys: [.fileResourceIdentifierKey]),
|
|
||||||
let resourceID = values.fileResourceIdentifier
|
|
||||||
else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
var shouldEnable = true
|
var shouldEnable = true
|
||||||
|
var resourceID : AnyObject?
|
||||||
|
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 {
|
||||||
let values = try? file.url.resourceValues(forKeys: [.fileResourceIdentifierKey]),
|
var thisID : AnyObject?
|
||||||
let thisID = values.fileResourceIdentifier
|
if (try? file.url.getResourceValue(&thisID, forKey:URLResourceKey.fileResourceIdentifierKey)) != nil {
|
||||||
{
|
if thisID != nil && resourceID!.isEqual(thisID!) {
|
||||||
if resourceID.isEqual(thisID) {
|
shouldEnable = false
|
||||||
shouldEnable = false
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -583,7 +591,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
return selectedFiles().count > 0
|
return selectedFiles().count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFileAtURL(url: URL) {
|
func createFileAtURL(url:NSURL) {
|
||||||
let type = ASFileType.guessForURL(url: url)
|
let type = ASFileType.guessForURL(url: url)
|
||||||
var firstPfx = ""
|
var firstPfx = ""
|
||||||
var prefix = ""
|
var prefix = ""
|
||||||
|
@ -615,13 +623,13 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
let dateFmt = DateFormatter()
|
let dateFmt = DateFormatter()
|
||||||
dateFmt.dateFormat = "yyyy-MM-dd"
|
dateFmt.dateFormat = "yyyy-MM-dd"
|
||||||
header = firstPfx + "\n" +
|
header = firstPfx + "\n" +
|
||||||
prefix + " Project: " + fileURL!.deletingLastPathComponent().lastPathComponent + "\n" +
|
prefix + " Project: " + fileURL!.URLByDeletingLastPathComponent!.lastPathComponent! + "\n" +
|
||||||
prefix + " File: " + url.lastPathComponent + "\n" +
|
prefix + " File: " + url.lastPathComponent! + "\n" +
|
||||||
prefix + " Created: " + dateFmt.string(from: Date()) + "\n" +
|
prefix + " Created: " + dateFmt.stringFromDate(NSDate()) + "\n" +
|
||||||
lastPfx + "\n\n"
|
lastPfx + "\n\n"
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
try header.write(to: url, atomically: true, encoding: String.Encoding.utf8)
|
try header.writeToURL(url, atomically: true, encoding: String.Encoding.utf8)
|
||||||
} catch _ {
|
} catch _ {
|
||||||
}
|
}
|
||||||
files.addFileURL(url: url)
|
files.addFileURL(url: url)
|
||||||
|
@ -667,14 +675,14 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
|
|
||||||
// MARK: Editor configuration
|
// MARK: Editor configuration
|
||||||
|
|
||||||
@IBAction func changeTheme(_ item: NSMenuItem) {
|
@IBAction func changeTheme(item: NSMenuItem) {
|
||||||
currentTheme = ACETheme(rawValue: UInt(item.tag)) ?? .xcode
|
currentTheme = ACETheme(rawValue: UInt(item.tag)) ?? .xcode
|
||||||
editor.setTheme(currentTheme)
|
editor.setTheme(currentTheme)
|
||||||
UserDefaults.standard.set(
|
UserDefaults.standard.set(
|
||||||
ACEThemeNames.humanName(for: currentTheme), forKey: kThemeKey)
|
ACEThemeNames.humanName(for: currentTheme), forKey: kThemeKey)
|
||||||
updateChangeCount(.changeDone)
|
updateChangeCount(.changeDone)
|
||||||
}
|
}
|
||||||
@IBAction func changeKeyboardHandler(_ item: NSMenuItem) {
|
@IBAction func changeKeyboardHandler(item: NSMenuItem) {
|
||||||
keyboardHandler = ACEKeyboardHandler(rawValue: UInt(item.tag))!
|
keyboardHandler = ACEKeyboardHandler(rawValue: UInt(item.tag))!
|
||||||
UserDefaults.standard.set(
|
UserDefaults.standard.set(
|
||||||
ACEKeyboardHandlerNames.humanName(for: keyboardHandler), forKey: kBindingsKey)
|
ACEKeyboardHandlerNames.humanName(for: keyboardHandler), forKey: kBindingsKey)
|
||||||
|
@ -683,18 +691,18 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
|
|
||||||
override func validateUserInterfaceItem(_ anItem: NSValidatedUserInterfaceItem) -> Bool {
|
override func validateUserInterfaceItem(_ anItem: NSValidatedUserInterfaceItem) -> Bool {
|
||||||
if let menuItem = anItem as? NSMenuItem {
|
if let menuItem = anItem as? NSMenuItem {
|
||||||
if menuItem.action == #selector(ASProjDoc.changeTheme(_:)) {
|
if menuItem.action == "changeTheme:" {
|
||||||
menuItem.state = (UInt(menuItem.tag) == currentTheme.rawValue ? NSOnState : NSOffState)
|
menuItem.state = (UInt(menuItem.tag) == currentTheme.rawValue ? NSOnState : NSOffState)
|
||||||
return true
|
return true
|
||||||
} else if menuItem.action == #selector(ASProjDoc.changeKeyboardHandler(_:)) {
|
} else if menuItem.action == "changeKeyboardHandler:" {
|
||||||
menuItem.state = (menuItem.tag == Int(keyboardHandler.rawValue) ? NSOnState : NSOffState)
|
menuItem.state = (menuItem.tag == Int(keyboardHandler.rawValue) ? NSOnState : NSOffState)
|
||||||
return true
|
return true
|
||||||
} else if menuItem.action == #selector(ASProjDoc.serialConnect(_:)) {
|
} else if menuItem.action == "serialConnect:" {
|
||||||
menuItem.title = port
|
menuItem.title = port
|
||||||
|
|
||||||
return true
|
return true
|
||||||
} else if menuItem.action == #selector(ASLibraries.importStandardLibrary(_:)) ||
|
} else if menuItem.action == "importStandardLibrary:" ||
|
||||||
menuItem.action == #selector(ASLibraries.importContribLibrary(_:))
|
menuItem.action == "importContribLibrary:"
|
||||||
{
|
{
|
||||||
return mainEditor is ASFileItem
|
return mainEditor is ASFileItem
|
||||||
}
|
}
|
||||||
|
@ -716,54 +724,54 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Issues
|
// MARK: Issues
|
||||||
@IBAction func jumpToIssue(_ sender: AnyObject) {
|
@IBAction func jumpToIssue(sender: AnyObject) {
|
||||||
let direction : Int = (sender as! NSMenuItem).tag
|
let direction : Int = (sender as! NSMenuItem).tag
|
||||||
if editors.views(in: .bottom).count == 0 {
|
if editors.views(in: .bottom).count == 0 {
|
||||||
editors.addView(auxEdit, in: .bottom)
|
editors.addView(auxEdit, in: .bottom)
|
||||||
|
|
||||||
let url = fileURL?.deletingLastPathComponent().appendingPathComponent(files.buildLog.path)
|
let url = fileURL?.URLByDeletingLastPathComponent?.URLByAppendingPathComponent(files.buildLog.path)
|
||||||
if url == nil {
|
if url == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var enc : String.Encoding = .utf8
|
var enc : UInt = 0
|
||||||
let contents = try? String(contentsOf:url!, usedEncoding:&enc)
|
let contents = try? NSString(contentsOfURL:url!, usedEncoding:&enc)
|
||||||
auxEdit.setString(contents ?? "")
|
auxEdit.setString(contents as? String ?? "")
|
||||||
editor.setMode(.text)
|
editor.setMode(.text)
|
||||||
editor.alphaValue = 1.0
|
editor.alphaValue = 1.0
|
||||||
}
|
}
|
||||||
let buildLog = auxEdit.string().components(separatedBy: "\n")
|
let buildLog = auxEdit.string().componentsSeparatedByString("\n")
|
||||||
let issueRe = try! NSRegularExpression(pattern: "(\\S+?):(\\d+):.*", options: [])
|
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, line.utf16.count)
|
let range = NSMakeRange(0, line.utf16.count)
|
||||||
if let match = issueRe.firstMatch(in: line, options:.anchored, range:range) {
|
if let match = issueRe.firstMatchInString(line, options:.Anchored, range:range) {
|
||||||
let file = match.rangeAt(1)
|
let file = match.rangeAtIndex(1)
|
||||||
let lineTxt = match.rangeAt(2)
|
let lineTxt = match.rangeAtIndex(2)
|
||||||
let nsline = line as NSString
|
let nsline = line as NSString
|
||||||
let lineNo = Int(nsline.substring(with: lineTxt))!
|
let lineNo = Int(nsline.substringWithRange(lineTxt))!
|
||||||
let fileName = nsline.substring(with: file) as NSString
|
let fileName = nsline.substringWithRange(file) as NSString
|
||||||
let fileURL : URL
|
let fileURL : NSURL
|
||||||
|
|
||||||
if fileName.hasPrefix("../../") {
|
if fileName.hasPrefix("../../") {
|
||||||
fileURL = files.dir.appendingPathComponent(fileName.substring(from: 6))
|
fileURL = files.dir.URLByAppendingPathComponent(fileName.substringFromIndex(6))
|
||||||
} else {
|
} else {
|
||||||
fileURL = URL(fileURLWithPath:fileName as String).standardizedFileURL
|
fileURL = NSURL(fileURLWithPath:fileName as String).URLByStandardizingPath!
|
||||||
}
|
}
|
||||||
|
|
||||||
jumpingToIssue = true
|
jumpingToIssue = true
|
||||||
if let values = try? fileURL.resourceValues(forKeys: [.fileResourceIdentifierKey]),
|
var resourceID : AnyObject?
|
||||||
let resourceID = values.fileResourceIdentifier
|
if (try? fileURL.getResourceValue(&resourceID, forKey:URLResourceKey.fileResourceIdentifierKey)) != nil && resourceID != nil {
|
||||||
{
|
|
||||||
files.apply {(node) in
|
files.apply {(node) in
|
||||||
if let file = node as? ASFileItem,
|
if let file = node as? ASFileItem {
|
||||||
let values = try? file.url.resourceValues(forKeys: [.fileResourceIdentifierKey]),
|
var thisID : AnyObject?
|
||||||
let thisID = values.fileResourceIdentifier,
|
if (try? file.url.getResourceValue(&thisID, forKey:URLResourceKey.fileResourceIdentifierKey)) != nil {
|
||||||
resourceID.isEqual(thisID)
|
if thisID != nil && resourceID!.isEqual(thisID!) {
|
||||||
{
|
self.selectNodeInOutline(selection: node)
|
||||||
self.selectNodeInOutline(selection: node)
|
self.editor.gotoLine(lineNo, column:0, animated:true)
|
||||||
self.editor.gotoLine(lineNo, column:0, animated:true)
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -801,11 +809,11 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
switch menu.title {
|
switch menu.title {
|
||||||
case "Boards":
|
case "Boards":
|
||||||
ASHardware.instance().buildBoardsMenu(menu: menu, recentBoards: recentBoards,
|
ASHardware.instance().buildBoardsMenu(menu: menu, recentBoards: recentBoards,
|
||||||
target: self, selector: #selector(ASProjDoc.selectBoard(_:)))
|
target: self, selector: "selectBoard:")
|
||||||
boardTool.setTitle(selectedBoard)
|
boardTool.setTitle(selectedBoard)
|
||||||
case "Programmers":
|
case "Programmers":
|
||||||
ASHardware.instance().buildProgrammersMenu(menu: menu, recentProgrammers: recentProgrammers,
|
ASHardware.instance().buildProgrammersMenu(menu: menu, recentProgrammers: recentProgrammers,
|
||||||
target: self, selector: #selector(ASProjDoc.selectProgrammer(_:)))
|
target: self, selector: "selectProgrammer:")
|
||||||
progTool.setTitle(selectedProgrammer)
|
progTool.setTitle(selectedProgrammer)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -838,7 +846,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func selectBoard(_ item: AnyObject) {
|
@IBAction func selectBoard(item: AnyObject) {
|
||||||
selectedBoard = (item as! NSMenuItem).title
|
selectedBoard = (item as! NSMenuItem).title
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -869,11 +877,11 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func selectProgrammer(_ item: AnyObject) {
|
@IBAction func selectProgrammer(item: AnyObject) {
|
||||||
selectedProgrammer = (item as! NSMenuItem).title
|
selectedProgrammer = (item as! NSMenuItem).title
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func selectPort(_ item: AnyObject) {
|
@IBAction func selectPort(item: AnyObject) {
|
||||||
port = (item as! NSPopUpButton).titleOfSelectedItem!
|
port = (item as! NSPopUpButton).titleOfSelectedItem!
|
||||||
portTool.setTitle(port)
|
portTool.setTitle(port)
|
||||||
}
|
}
|
||||||
|
@ -909,26 +917,26 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
return NSSet(objects: "hasValidPort", "hasUploadProtocol", "programmer")
|
return NSSet(objects: "hasValidPort", "hasUploadProtocol", "programmer")
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func uploadProject(_ sender: AnyObject) {
|
@IBAction func uploadProject(sender: AnyObject) {
|
||||||
builder.continuation = {
|
builder.continuation = {
|
||||||
self.selectNodeInOutline(selection: self.files.uploadLog)
|
self.selectNodeInOutline(selection: self.files.uploadLog)
|
||||||
DispatchQueue.main.async(execute: {
|
dispatch_async(dispatch_get_main_queue(), {
|
||||||
self.builder.uploadProject(board: self.board, programmer:self.programmer, port:self.port)
|
self.builder.uploadProject(board: self.board, programmer:self.programmer, port:self.port)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
buildProject(sender)
|
buildProject(sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func uploadTerminal(_: AnyObject) {
|
@IBAction func uploadTerminal(sender: AnyObject) {
|
||||||
builder.uploadProject(board: board, programmer:programmer, port:port, mode:.Interactive)
|
builder.uploadProject(board: board, programmer:programmer, port:port, mode:.Interactive)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func burnBootloader(_: AnyObject) {
|
@IBAction func burnBootloader(sender: AnyObject) {
|
||||||
self.selectNodeInOutline(selection: self.files.uploadLog)
|
self.selectNodeInOutline(selection: self.files.uploadLog)
|
||||||
builder.uploadProject(board: board, programmer:programmer, port:port, mode:.BurnBootloader)
|
builder.uploadProject(board: board, programmer:programmer, port:port, mode:.BurnBootloader)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func disassembleProject(_ sender: AnyObject) {
|
@IBAction func disassembleProject(sender: AnyObject) {
|
||||||
builder.continuation = {
|
builder.continuation = {
|
||||||
self.selectNodeInOutline(selection: self.files.disassembly)
|
self.selectNodeInOutline(selection: self.files.disassembly)
|
||||||
self.builder.disassembleProject(board: self.board)
|
self.builder.disassembleProject(board: self.board)
|
||||||
|
@ -936,7 +944,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
|
||||||
buildProject(sender)
|
buildProject(sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func serialConnect(_: AnyObject) {
|
@IBAction func serialConnect(sender: AnyObject) {
|
||||||
ASSerialWin.showWindowWithPort(port: port)
|
ASSerialWin.showWindowWithPort(port: port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,14 +37,14 @@ NSString * kASSerialPortsChanged = @"PortsChanged";
|
||||||
watchSlashDev =
|
watchSlashDev =
|
||||||
dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_WRITE, dispatch_get_main_queue());
|
dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_WRITE, dispatch_get_main_queue());
|
||||||
dispatch_source_set_event_handler(watchSlashDev, ^{
|
dispatch_source_set_event_handler(watchSlashDev, ^{
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:kASSerialPortsChanged object: nil];
|
[[NotificationCenter defaultCenter] postNotificationName:kASSerialPortsChanged object: nil];
|
||||||
});
|
});
|
||||||
dispatch_resume(watchSlashDev);
|
dispatch_resume(watchSlashDev);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray<NSString *> *)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 [[FileManager defaultManager] contentsOfDirectoryAtPath:@"/dev" error: nil]) {
|
||||||
if ([[port substringToIndex:2] isEqualToString:@"cu"])
|
if ([[port substringToIndex:2] isEqualToString:@"cu"])
|
||||||
[cuPorts addObject:[port substringFromIndex:3]];
|
[cuPorts addObject:[port substringFromIndex:3]];
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ class ASSerialWin: NSWindowController {
|
||||||
@IBOutlet weak var inputLine : NSTextField!
|
@IBOutlet weak var inputLine : NSTextField!
|
||||||
@IBOutlet weak var logView : ACEView!
|
@IBOutlet weak var logView : ACEView!
|
||||||
|
|
||||||
var portDefaults = [String: Any]()
|
|
||||||
var baudRate : Int = 9600 {
|
var baudRate : Int = 9600 {
|
||||||
didSet(oldRate) {
|
didSet(oldRate) {
|
||||||
if portHandle != nil {
|
if portHandle != nil {
|
||||||
|
@ -42,8 +41,9 @@ class ASSerialWin: NSWindowController {
|
||||||
dynamic var portHandle : FileHandle?
|
dynamic var portHandle : FileHandle?
|
||||||
var currentTheme : ACETheme = .xcode
|
var currentTheme : ACETheme = .xcode
|
||||||
var fontSize : UInt = 12
|
var fontSize : UInt = 12
|
||||||
|
var portDefaults = [String: AnyObject]()
|
||||||
var shouldReconnect = false
|
var shouldReconnect = false
|
||||||
dynamic var task : Process?
|
dynamic var task : Task?
|
||||||
|
|
||||||
class func showWindowWithPort(port: String) {
|
class func showWindowWithPort(port: String) {
|
||||||
if let existing = serialInstances[port] {
|
if let existing = serialInstances[port] {
|
||||||
|
@ -54,7 +54,7 @@ class ASSerialWin: NSWindowController {
|
||||||
newInstance.showWindow(self)
|
newInstance.showWindow(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class func showWindowWithPort(port: String, task: Process, speed: Int) {
|
class func showWindowWithPort(port: String, task: Task, speed: Int) {
|
||||||
if let existing = serialInstances[port] {
|
if let existing = serialInstances[port] {
|
||||||
existing.showWindowWithTask(task: task, speed:speed)
|
existing.showWindowWithTask(task: task, speed:speed)
|
||||||
} else {
|
} else {
|
||||||
|
@ -116,10 +116,10 @@ class ASSerialWin: NSWindowController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
termination = NotificationCenter.default.addObserver(forName: Process.didTerminateNotification,
|
termination = NotificationCenter.default.addObserver(forName: Task.didTerminateNotification,
|
||||||
object: nil, queue: nil, using:
|
object: nil, queue: nil, using:
|
||||||
{ (notification: Notification) in
|
{ (notification: Notification) in
|
||||||
if notification.object as? Process == self.task {
|
if notification.object as? Task == self.task {
|
||||||
self.task = nil
|
self.task = nil
|
||||||
self.portHandle = nil
|
self.portHandle = nil
|
||||||
}
|
}
|
||||||
|
@ -161,17 +161,15 @@ class ASSerialWin: NSWindowController {
|
||||||
serialData = ""
|
serialData = ""
|
||||||
logView.setString(serialData)
|
logView.setString(serialData)
|
||||||
readHandle.readabilityHandler = {(handle) in
|
readHandle.readabilityHandler = {(handle) in
|
||||||
if let newData = handle.availableDataIgnoringExceptions(),
|
let newData = handle.availableDataIgnoringExceptions()
|
||||||
let newString = String(data: newData, encoding: String.Encoding.ascii)
|
let newString = NSString(data: newData, encoding: String.Encoding.ascii) as! String
|
||||||
{
|
self.serialData += newString
|
||||||
self.serialData += newString
|
DispatchQueue.main.async(execute: { () -> Void in
|
||||||
DispatchQueue.main.async(execute: {
|
self.logView.setString(self.serialData)
|
||||||
self.logView.setString(self.serialData)
|
if self.scrollToBottom {
|
||||||
if self.scrollToBottom {
|
self.logView.gotoLine(1000000000, column: 0, animated: true)
|
||||||
self.logView.gotoLine(1000000000, column: 0, animated: true)
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +180,7 @@ class ASSerialWin: NSWindowController {
|
||||||
portHandle?.write(data)
|
portHandle?.write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func showWindowWithTask(task: Process, speed:Int) {
|
func showWindowWithTask(task: Task, speed:Int) {
|
||||||
if portHandle != nil {
|
if portHandle != nil {
|
||||||
connect(self)
|
connect(self)
|
||||||
}
|
}
|
||||||
|
@ -235,7 +233,7 @@ class ASSerialWin: NSWindowController {
|
||||||
|
|
||||||
// MARK: Editor configuration
|
// MARK: Editor configuration
|
||||||
|
|
||||||
@IBAction func changeTheme(_ item: NSMenuItem) {
|
@IBAction func changeTheme(item: NSMenuItem) {
|
||||||
let userDefaults = UserDefaults.standard
|
let userDefaults = UserDefaults.standard
|
||||||
currentTheme = ACETheme(rawValue: UInt(item.tag)) ?? .xcode
|
currentTheme = ACETheme(rawValue: UInt(item.tag)) ?? .xcode
|
||||||
logView.setTheme(currentTheme)
|
logView.setTheme(currentTheme)
|
||||||
|
@ -244,7 +242,7 @@ class ASSerialWin: NSWindowController {
|
||||||
portDefaults["Theme"] = themeName
|
portDefaults["Theme"] = themeName
|
||||||
updatePortDefaults()
|
updatePortDefaults()
|
||||||
}
|
}
|
||||||
@IBAction func changeKeyboardHandler(_ item: NSMenuItem) {
|
@IBAction func changeKeyboardHandler(item: NSMenuItem) {
|
||||||
keyboardHandler = ACEKeyboardHandler(rawValue: UInt(item.tag))!
|
keyboardHandler = ACEKeyboardHandler(rawValue: UInt(item.tag))!
|
||||||
UserDefaults.standard.set(
|
UserDefaults.standard.set(
|
||||||
ACEKeyboardHandlerNames.humanName(for: keyboardHandler), forKey: "Bindings")
|
ACEKeyboardHandlerNames.humanName(for: keyboardHandler), forKey: "Bindings")
|
||||||
|
@ -253,10 +251,10 @@ class ASSerialWin: NSWindowController {
|
||||||
|
|
||||||
func validateUserInterfaceItem(anItem: NSValidatedUserInterfaceItem) -> Bool {
|
func validateUserInterfaceItem(anItem: NSValidatedUserInterfaceItem) -> Bool {
|
||||||
if let menuItem = anItem as? NSMenuItem {
|
if let menuItem = anItem as? NSMenuItem {
|
||||||
if menuItem.action == #selector(ASSerialWin.changeTheme(_:)) {
|
if menuItem.action == Selector(("changeTheme:")) {
|
||||||
menuItem.state = (UInt(menuItem.tag) == currentTheme.rawValue ? NSOnState : NSOffState)
|
menuItem.state = (UInt(menuItem.tag) == currentTheme.rawValue ? NSOnState : NSOffState)
|
||||||
return true
|
return true
|
||||||
} else if menuItem.action == #selector(ASSerialWin.changeKeyboardHandler(_:)) {
|
} else if menuItem.action == Selector(("changeKeyboardHandler:")) {
|
||||||
menuItem.state = (menuItem.tag == Int(keyboardHandler.rawValue) ? NSOnState : NSOffState)
|
menuItem.state = (menuItem.tag == Int(keyboardHandler.rawValue) ? NSOnState : NSOffState)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,9 +78,9 @@ def parseInoFiles
|
||||||
# Find protypes:
|
# Find protypes:
|
||||||
prototypes = contents.dup
|
prototypes = contents.dup
|
||||||
# - Strip comments, quoted strings, and preprocessor directives
|
# - Strip comments, quoted strings, and preprocessor directives
|
||||||
prototypes.gsub!(%r{'(?:\\'|[^'])+'|"(?:\\"|[^"])*"|//.*?$|/\*.*?\*/|^\s*?#.*?$}m, ' ')
|
prototypes.gsub!(%r{'(?:[^']|\\')+'|"(?:[^"]|\\")*"|//.*?$|/\*.*?\*/|^\s*?#.*?$}m, ' ')
|
||||||
# Collapse braces
|
# Collapse braces
|
||||||
while prototypes.sub!(/(\{)([^{}]+|\{[^{}]*\})/m, '\1') do
|
while prototypes.sub!(/(\{)(?:[^{}]+|\{[^{}]*\})/m, '\1') do
|
||||||
end
|
end
|
||||||
existingProto = {}
|
existingProto = {}
|
||||||
prototypes.scan(/[\w\[\]\*]+\s+[&\[\]\*\w\s]+\([&,\[\]\*\w\s]*\)(?=\s*;)/) {|p|
|
prototypes.scan(/[\w\[\]\*]+\s+[&\[\]\*\w\s]+\([&,\[\]\*\w\s]*\)(?=\s*;)/) {|p|
|
||||||
|
@ -92,7 +92,7 @@ def parseInoFiles
|
||||||
proto << p+";\n" unless existingProto[p]
|
proto << p+";\n" unless existingProto[p]
|
||||||
}
|
}
|
||||||
contents.each_line do |line|
|
contents.each_line do |line|
|
||||||
if line =~ %r{^\s*#include\s+[<"](.*)[">]\s*(#.*|/\*.*?\*/\s*|//.*)?$}
|
if line =~ /^\s*#include\s+[<"](.*)[">]\s*(#.*)?$/
|
||||||
addLibrary($1)
|
addLibrary($1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
20
README.md
20
README.md
|
@ -1,20 +0,0 @@
|
||||||
# AVRsack
|
|
||||||
|
|
||||||
`AVRsack` is an integrated development environment for the Atmel AVR series of microcontrollers.
|
|
||||||
It is designed to be an alternative for the Arduino 1.0.x application, offering:
|
|
||||||
|
|
||||||
* A more powerful text editor with a variety of styles.</li>
|
|
||||||
* A more powerful build system with incremental rebuilds.</li>
|
|
||||||
* A more powerful upload system with finer grained control over logging.</li>
|
|
||||||
* Full build/upload logs without arbitrary size restrictions.</li>
|
|
||||||
* Support for handling multiple simultaneous serial ports.</li>
|
|
||||||
* Support for assembly programming and disassembly of object code.</li>
|
|
||||||
* Support for alternate AVR toolchains, such as [Crosspack-AVR](https://www.obdev.at/products/crosspack/index.html)
|
|
||||||
|
|
||||||
`AVRsack` was written and designed by Matthias Neeracher <microtherion@gmail.com>
|
|
||||||
|
|
||||||
For editing text, `AVRsack` relies on Michael Robinson's [ACEView](https://github.com/faceleg/ACEView),
|
|
||||||
a Cocoa wrapper for the [Ace](http://ace.c9.io) code editor.
|
|
||||||
|
|
||||||
![Basic screenshot]
|
|
||||||
(https://github.com/microtherion/AVRsack/raw/master/Screenshots/AVRsack.png)
|
|
Binary file not shown.
Before Width: | Height: | Size: 414 KiB |
Loading…
Reference in New Issue
Block a user