Modernize ASFileTree

This commit is contained in:
Matthias Neeracher 2016-11-13 13:00:29 +01:00 committed by Matthias Neeracher
parent 25f904b606
commit 32d8adb1b1
2 changed files with 77 additions and 58 deletions

View File

@ -17,8 +17,8 @@ enum ASFileType : String {
case AsmFile = "source.asm" case AsmFile = "source.asm"
case Markdown = "doc.md" case Markdown = "doc.md"
static func guessForURL(url: NSURL) -> ASFileType { static func guessForURL(url: URL) -> ASFileType {
switch url.pathExtension!.lowercased { switch url.pathExtension.lowercased() {
case "hpp", "hh", "h": case "hpp", "hh", "h":
return .Header return .Header
case "c": case "c":
@ -64,13 +64,16 @@ class ASFileNode : Equatable {
func nodeName() -> String { func nodeName() -> String {
return "" return ""
} }
func apply(closure:(ASFileNode)->()) { func apply(closure:(ASFileNode)->()) {
closure(self) closure(self)
} }
func propertyList(rootPath: String) -> AnyObject {
return "" func propertyList(rootPath: String) -> Dictionary<String, AnyObject> {
return [:]
} }
class func readPropertyList(prop: NSDictionary, rootURL: NSURL) -> ASFileNode {
class func readPropertyList(prop: Dictionary<String, AnyObject>, rootURL: URL) -> ASFileNode {
switch prop[kTypeKey] as! String { switch prop[kTypeKey] as! String {
case kNodeTypeProject: case kNodeTypeProject:
return ASProject(prop, withRootURL:rootURL) return ASProject(prop, withRootURL:rootURL)
@ -83,15 +86,19 @@ class ASFileNode : Equatable {
abort() abort()
} }
} }
func paths(rootPath: String) -> [String] { func paths(rootPath: String) -> [String] {
return [String]() return [String]()
} }
func exists() -> Bool { func exists() -> Bool {
return true return true
} }
func modDate() -> NSDate? {
func modDate() -> Date? {
return nil; return nil;
} }
func revision() -> String? { func revision() -> String? {
return nil; return nil;
} }
@ -108,6 +115,7 @@ class ASLogNode : ASFileNode {
self.path = path self.path = path
super.init(name: name) super.init(name: name)
} }
override func nodeName() -> String { override func nodeName() -> String {
return "📜 "+name return "📜 "+name
} }
@ -126,30 +134,36 @@ class ASFileGroup : ASFileNode {
self.expanded = true self.expanded = true
super.init(name: name) super.init(name: name)
} }
init(_ prop: NSDictionary, withRootURL rootURL: NSURL) {
init(_ prop: Dictionary<String, AnyObject>, withRootURL rootURL: URL) {
expanded = prop[kExpandedKey] as! Bool expanded = prop[kExpandedKey] as! Bool
children = [] children = []
for child in (prop[kChildrenKey] as! [NSDictionary]) { for child in (prop[kChildrenKey] as! [Dictionary<String, AnyObject>]) {
children.append(ASFileNode.readPropertyList(prop: child, rootURL: rootURL)) children.append(ASFileNode.readPropertyList(prop: child, rootURL: rootURL))
} }
super.init(name: prop[kNameKey] as! String) super.init(name: prop[kNameKey] as! String)
} }
override func nodeName() -> String { override func nodeName() -> String {
return (expanded ? "📂" : "📁")+" "+name return (expanded ? "📂" : "📁")+" "+name
} }
override func apply(closure: (ASFileNode) -> ()) { override func apply(closure: (ASFileNode) -> ()) {
super.apply(closure: closure) super.apply(closure: closure)
for child in children { for child in children {
child.apply(closure: closure) child.apply(closure: closure)
} }
} }
func childrenPropertyList(rootPath: String) -> [AnyObject] { 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) -> AnyObject {
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)] kChildrenKey: childrenPropertyList(rootPath: rootPath)]
} }
override func paths(rootPath: String) -> [String] { override func paths(rootPath: String) -> [String] {
var allPaths = [String]() var allPaths = [String]()
for child in children { for child in children {
@ -165,57 +179,61 @@ class ASProject : ASFileGroup {
override init(name: String = "") { override init(name: String = "") {
super.init(name: name) super.init(name: name)
} }
override init(_ prop: NSDictionary, withRootURL rootURL: NSURL) {
override init(_ prop: Dictionary<String, AnyObject>, withRootURL rootURL: URL) {
super.init(prop, withRootURL:rootURL) super.init(prop, withRootURL:rootURL)
name = rootURL.lastPathComponent! name = rootURL.lastPathComponent
} }
override func nodeName() -> String { override func nodeName() -> String {
return "📘 "+name return "📘 "+name
} }
} }
class ASFileItem : ASFileNode { class ASFileItem : ASFileNode {
var url : NSURL var url : URL
var type : ASFileType var type : ASFileType
private let kPathKey = "Path" private let kPathKey = "Path"
private let kKindKey = "Kind" private let kKindKey = "Kind"
init(url: NSURL, type: ASFileType) { init(url: URL, type: ASFileType) {
self.url = url self.url = url
self.type = type self.type = type
super.init(name:url.lastPathComponent!) super.init(name:url.lastPathComponent)
} }
init(_ prop: NSDictionary, withRootURL rootURL: NSURL) {
init(_ prop: Dictionary<String, AnyObject>, withRootURL rootURL: URL) {
type = ASFileType(rawValue: prop[kKindKey] as! String)! type = ASFileType(rawValue: prop[kKindKey] as! String)!
if let relativeURL = NSURL(string: prop[kPathKey] as! String, relativeToURL: rootURL) { let path = prop[kPathKey] as! NSString
url = relativeURL.URLByStandardizingPath! if path.isAbsolutePath {
url = URL(fileURLWithPath:path as String).standardizedFileURL
} else { } else {
url = NSURL(fileURLWithPath:(prop[kPathKey] as! String)).standardizingPath! url = URL(fileURLWithPath: path as String, relativeTo: rootURL).standardizedFileURL
} }
if !url.checkResourceIsReachableAndReturnError(nil) { if try! !url.checkResourceIsReachable() {
// //
// 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.
// //
let urlDir = url.deletingLastPathComponent let urlDir = url.deletingLastPathComponent()
let newName = rootURL.URLByAppendingPathExtension(url.pathExtension!).lastPathComponent! let newName = rootURL.appendingPathExtension(url.pathExtension).lastPathComponent
if let altURL = urlDir?.URLByAppendingPathComponent(newName) { let altURL = urlDir.appendingPathComponent(newName)
if altURL.checkResourceIsReachableAndReturnError(nil) { if try! altURL.checkResourceIsReachable() {
url = altURL url = altURL
} }
} }
super.init(name:url.lastPathComponent)
} }
super.init(name:url.lastPathComponent!)
}
override func nodeName() -> String { override func nodeName() -> String {
return "📄 "+name return "📄 "+name
} }
func relativePath(relativeTo: String) -> String { func relativePath(relativeTo: String) -> String {
let path = (url.path! as NSString).resolvingSymlinksInPath let path = (url.path as NSString).resolvingSymlinksInPath
let relComp = relativeTo.componentsSeparatedByString("/") as [String] let relComp = relativeTo.components(separatedBy: "/") as [String]
let pathComp = path.componentsSeparatedByString("/") as [String] let pathComp = path.components(separatedBy: "/") as [String]
let relCount = relComp.count let relCount = relComp.count
let pathCount = pathComp.count let pathCount = pathComp.count
@ -231,61 +249,62 @@ class ASFileItem : ASFileNode {
return path return path
} }
let resComp = Array(count: relCount-matchComp, repeatedValue: "..")+pathComp[matchComp..<pathCount] let resComp = Array(repeating: "..", count: relCount-matchComp)+pathComp[matchComp..<pathCount]
return resComp.joinWithSeparator("/") return resComp.joined(separator: "/")
} }
override func propertyList(rootPath: String) -> AnyObject {
return [kTypeKey: kNodeTypeFile, kKindKey: type.rawValue, kPathKey: relativePath(rootPath)] override func propertyList(rootPath: String) -> Dictionary<String, AnyObject> {
return [kTypeKey: kNodeTypeFile, kKindKey: type.rawValue,
kPathKey: relativePath(relativeTo: rootPath)]
} }
override func paths(rootPath: String) -> [String] { override func paths(rootPath: String) -> [String] {
return [relativePath(relativeTo: rootPath)] return [relativePath(relativeTo: rootPath)]
} }
override func exists() -> Bool { override func exists() -> Bool {
return url.checkResourceIsReachableAndReturnError(nil) return try! url.checkResourceIsReachable()
}
override func modDate() -> NSDate? {
var date: AnyObject?
do {
try url.getResourceValue(&date, forKey: URLResourceKey.contentModificationDateKey)
return date as? NSDate
} catch _ {
return nil
} }
override func modDate() -> Date? {
let values = try? url.resourceValues(forKeys: [URLResourceKey.contentModificationDateKey])
return values?.contentModificationDate
} }
override func revision() -> String? { override func revision() -> String? {
let task = Task() 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
task.standardError = FileHandle.nullDevice task.standardError = FileHandle.nullDevice
task.arguments = [url.path!] task.arguments = [url.path]
task.launch() task.launch()
return NSString(data: outputPipe.fileHandleForReading.readDataToEndOfFile(), return String(data: outputPipe.fileHandleForReading.readDataToEndOfFile(), encoding: String.Encoding.utf8)
encoding: String.Encoding.utf8) as? String
} }
} }
class ASFileTree : NSObject, NSOutlineViewDataSource { class ASFileTree : NSObject, NSOutlineViewDataSource {
var root = ASProject() var root = ASProject()
var dir = NSURL() var dir = URL(fileURLWithPath: "/")
var buildLog = ASLogNode(name: "Build Log", path: "build/build.log") var buildLog = ASLogNode(name: "Build Log", path: "build/build.log")
var uploadLog = ASLogNode(name: "Upload Log", path: "build/upload.log") var uploadLog = ASLogNode(name: "Upload Log", path: "build/upload.log")
var disassembly = ASLogNode(name: "Disassembly", path: "build/disasm.log") var disassembly = ASLogNode(name: "Disassembly", path: "build/disasm.log")
var dragged = [ASFileNode]() var dragged = [ASFileNode]()
func addFileURL(url: NSURL, omitUnknown: Bool = true) { func addFileURL(url: URL, omitUnknown: Bool = true) {
let type = ASFileType.guessForURL(url: url) let type = ASFileType.guessForURL(url: url)
if !omitUnknown || type != .Unknown { if !omitUnknown || type != .Unknown {
root.children.append(ASFileItem(url: url.standardizingPath!, type: type)) root.children.append(ASFileItem(url: url.standardizedFileURL, type: type))
} }
} }
func setProjectURL(url: NSURL) { func setProjectURL(url: URL) {
root.name = url.deletingPathExtension!.lastPathComponent root.name = url.deletingPathExtension().lastPathComponent
dir = url.URLByDeletingLastPathComponent!.URLByStandardizingPath! dir = url.deletingLastPathComponent().standardizedFileURL
} }
func projectPath() -> String { func projectPath() -> String {
return (dir.path! as NSString).resolvingSymlinksInPath return (dir.path as NSString).resolvingSymlinksInPath
} }
func apply(closure: (ASFileNode) -> ()) { func apply(closure: (ASFileNode) -> ()) {
root.apply(closure: closure) root.apply(closure: closure)
@ -293,7 +312,7 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
func propertyList() -> AnyObject { func propertyList() -> AnyObject {
return root.propertyList(rootPath: projectPath()) return root.propertyList(rootPath: projectPath())
} }
func readPropertyList(prop: NSDictionary) { func readPropertyList(prop: Dictionary<String, AnyObject>) {
root = ASFileNode.readPropertyList(prop: prop, rootURL:dir) as! ASProject root = ASFileNode.readPropertyList(prop: prop, rootURL:dir) as! ASProject
} }
var paths : [String] { var paths : [String] {
@ -336,7 +355,7 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
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(NSData(), forType: kLocalReorderPasteboardType) pasteboard.setData(Data(), forType: kLocalReorderPasteboardType)
return true return true
} }
@ -382,12 +401,12 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
let origParent = outlineView.parent(forItem: item) as! ASFileGroup let origParent = outlineView.parent(forItem: item) as! ASFileGroup
let origIndex = origParent.children.index(of: item)! let origIndex = origParent.children.index(of: item)!
origParent.children.remove(at: origIndex) origParent.children.remove(at: origIndex)
outlineView.removeItemsAtIndexes(NSIndexSet(index:origIndex), inParent:origParent, withAnimation:NSTableViewAnimationOptions.EffectNone) outlineView.removeItems(at:IndexSet(integer:origIndex), inParent:origParent, withAnimation:[])
if origParent == parent && insertAtIndex > origIndex { if origParent == parent && insertAtIndex > origIndex {
insertAtIndex -= 1 insertAtIndex -= 1
} }
parent.children.insert(item, at:insertAtIndex) parent.children.insert(item, at:insertAtIndex)
outlineView.insertItemsAtIndexes(NSIndexSet(index:insertAtIndex), inParent: parent, withAnimation:NSTableViewAnimationOptions.EffectGap) outlineView.insertItems(at:IndexSet(integer:insertAtIndex), inParent: parent, withAnimation:NSTableViewAnimationOptions.effectGap)
insertAtIndex += 1 insertAtIndex += 1
} }
outlineView.endUpdates() outlineView.endUpdates()

View File

@ -229,7 +229,7 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
if let fontSz = projectData[kFontSizeKey] as? Int { if let fontSz = projectData[kFontSizeKey] as? Int {
fontSize = UInt(fontSz) fontSize = UInt(fontSz)
} }
files.readPropertyList(projectData[kFilesKey] as! NSDictionary) files.readPropertyList(prop: projectData[kFilesKey] as? Dictionary<String, AnyObject> ?? [:])
board = (projectData[kBoardKey] as? String) ?? board board = (projectData[kBoardKey] as? String) ?? board
programmer = (projectData[kProgrammerKey] as? String) ?? programmer programmer = (projectData[kProgrammerKey] as? String) ?? programmer
port = (projectData[kPortKey] as? String) ?? port port = (projectData[kPortKey] as? String) ?? port