diff --git a/Sources/GitSyncMac/library/CommitDP.swift b/Sources/GitSyncMac/library/CommitDP.swift index f494d67e2..b3b6cce52 100644 --- a/Sources/GitSyncMac/library/CommitDP.swift +++ b/Sources/GitSyncMac/library/CommitDP.swift @@ -1,53 +1,53 @@ import Foundation @testable import Utils /** - * DISCUSSION: The reason we have prevCommits, is to provide an easy way to find which commit from a repo was added to CommitDB + * - DISCUSSION: The reason we have prevCommits, is to provide an easy way to find which commit from a repo was added to CommitDB * CommitDB is a wrapper for git repos. Instead of querrying the many git repos at all time, we rather inteligently cache the data because some parts of the GUI frequently asks for an updated state of the last 100 commits -> this would be cpu instensive to recalculate often so we cache the data instead, and only ask the repos for data that isnt cached - * TODO: it would be significatly faster if we knew the freshesht commit for each repo. -> store a Dict of repoHash, descChronoDate -> and assert on each add wether to store a new freshest item or not + * - TODO: it would be significatly faster if we knew the freshesht commit for each repo. -> store a Dict of repoHash, descChronoDate -> and assert on each add wether to store a new freshest item or not */ -class CommitDP:DataProvider{ - static var max:Int = 100 +class CommitDP: DataProvider { + static var max: Int = 100 } extension CommitDP{ /** * New */ - func add(rawCommitData:String,_ repoTitle:String){ - let processedCommitData:ProcessedCommitData = ProcessedCommitData(rawCommitData:rawCommitData,repoTitle) - let commitDict:[String:String] = processedCommitData.dict + func add(rawCommitData: String, _ repoTitle: String){ + let processedCommitData: ProcessedCommitData = ProcessedCommitData(rawCommitData:rawCommitData,repoTitle) + let commitDict: [String: String] = processedCommitData.dict addCommitItem(commitDict) } /** * Adds An item to the sortedArr (at the correct index according to descending chronology, by using a custom binarySearch method) - * NOTE: Items must be added one after the other. A Bulk add method wouldn't work, unless you iterate one by one I guess??? + * - NOTE: Items must be added one after the other. A Bulk add method wouldn't work, unless you iterate one by one I guess??? */ func addCommitItem(_ item:[String:String]){ let closestIdx:Int = CommitDP.closestIndex(items, item, 0, items.endIndex) if(!Utils.existAtOrBefore(items,closestIdx,item)){//TODO: ⚠️️ ideally this should be handled in the binarySearch algo, but this is a quick fix, that doesn't hurt performance // Swift.print("📝 insert at: \(closestIdx) item.date: \(GitDateUtils.gitTime(item["sortableDate"]!))" ) - self.add(item, closestIdx,false) + self.add(item, closestIdx, false) //_ = items.insertAt(item, closestIdx) } - if(items.count > CommitDP.max){_ = items.popLast()}/*keeps the array at max items*/ + if items.count > CommitDP.max { _ = items.popLast() }/*keeps the array at max items*/ } /** * This binarySearch finds a suitable index to insert an item in a sorted list (a regular binarySearch would return nil if no match is found, this implmentation returns the closestIndex) - * NOTE: Binary search, also known as half-interval search or logarithmic search, is a search algorithm that finds the position of a target value within a sorted array. - * NOTE: Binary search compares the target value to the middle element of the array; if they are unequal, the half in which the target cannot lie is eliminated and the search continues on the remaining half until it is successful. - * NOTE: Binary search runs in at worst logarithmic time, making O(log n) comparisons, where n is the number of elements in the array and log is the logarithm. Binary search takes only constant (O(1)) space, meaning that the space taken by the algorithm is the same for any number of elements in the array.[5] Although specialized data structures designed for fast searching—such as hash tables—can be searched more efficiently, binary search applies to a wider range of search problems. - * NOTE: This implementation of binary search is recursive (it calls it self) (Binary search is recursive in nature because you apply the same logic over and over again to smaller and smaller subarrays.) - * IMPORTANT: ⚠️️ Although the idea is simple, implementing binary search correctly requires attention to some subtleties about its exit conditions and midpoint calculation. - * IMPORTANT: ⚠️️ Note that the numbers array is sorted. The binary search algorithm does not work otherwise! - * DISCUSSION: Is it a problem that the array must be sorted first? It depends. Keep in mind that sorting takes time -- the combination of binary search plus sorting may be slower than doing a simple linear search. Binary search shines in situations where you sort just once and then do many searches. - * TRIVIA: YOu can also implement binary serach as iterative implementation by using a while loop - * TODO: use range instead of start and end int?!? + * - NOTE: Binary search, also known as half-interval search or logarithmic search, is a search algorithm that finds the position of a target value within a sorted array. + * - NOTE: Binary search compares the target value to the middle element of the array; if they are unequal, the half in which the target cannot lie is eliminated and the search continues on the remaining half until it is successful. + * - NOTE: Binary search runs in at worst logarithmic time, making O(log n) comparisons, where n is the number of elements in the array and log is the logarithm. Binary search takes only constant (O(1)) space, meaning that the space taken by the algorithm is the same for any number of elements in the array.[5] Although specialized data structures designed for fast searching—such as hash tables—can be searched more efficiently, binary search applies to a wider range of search problems. + * - NOTE: This implementation of binary search is recursive (it calls it self) (Binary search is recursive in nature because you apply the same logic over and over again to smaller and smaller subarrays.) + * - IMPORTANT: ⚠️️ Although the idea is simple, implementing binary search correctly requires attention to some subtleties about its exit conditions and midpoint calculation. + * - IMPORTANT: ⚠️️ Note that the numbers array is sorted. The binary search algorithm does not work otherwise! + * - DISCUSSION: Is it a problem that the array must be sorted first? It depends. Keep in mind that sorting takes time -- the combination of binary search plus sorting may be slower than doing a simple linear search. Binary search shines in situations where you sort just once and then do many searches. + * - TRIVIA: YOu can also implement binary serach as iterative implementation by using a while loop + * - Fixme: use range instead of start and end int?!? */ - static func closestIndex(_ arr:[[String:String]],_ i:[String:String],_ start:Int,_ end:Int) -> Int{ + static func closestIndex(_ arr: [[String: String]], _ i: [String: String], _ start: Int, _ end: Int) -> Int { if(start == end){ //Swift.print("❤️️ i doesn't exist, this is the closest at: \(start) ") return start } - let mid:Int = start + ((end - start) / 2)/*start + middle of the distance between start and end*/ + let mid: Int = start + ((end - start) / 2)/*start + middle of the distance between start and end*/ //Swift.print("mid: " + "\(mid)") //Swift.print("arr[mid]: " + "\(arr[mid])") if(i["sortableDate"]!.int > arr[mid]["sortableDate"]!.int){/*index is in part1*/ @@ -55,7 +55,7 @@ extension CommitDP{ return closestIndex(arr,i,start,mid) }else if(i["sortableDate"]!.int < arr[mid]["sortableDate"]!.int){/*index is in part2*/ //Swift.print("b") - return closestIndex(arr,i,mid+1,end) + return closestIndex(arr, i, mid + 1, end) }else{/*index is at middleIndex*/ //Swift.print("at middle: \(mid)") return mid @@ -65,27 +65,27 @@ extension CommitDP{ private class Utils{ /** * Asserts if an item is at or before PARAM: idx - * NOTE: Usefull in conjunction with ArrayModifier.insertAt()// to assert if an item already exists at that idx or not. to avoid dups + * - NOTE: Usefull in conjunction with ArrayModifier.insertAt()// to assert if an item already exists at that idx or not. to avoid dups */ - static func existAtOrBefore(_ arr:[[String:String]],_ idx:Int, _ item:[String:String]) -> Bool { - func itemAlreadyExistAtIdx()->Bool {return (arr.valid(idx) && arr[idx]["hash"] == item["hash"]) } - func itemExistsAtIdxBefore()->Bool {return (arr.valid(idx-1) && arr[idx-1]["hash"] == item["hash"])} + static func existAtOrBefore(_ arr: [[String: String]], _ idx: Int, _ item: [String: String]) -> Bool { + func itemAlreadyExistAtIdx() -> Bool { return (arr.valid(idx) && arr[idx]["hash"] == item["hash"]) } + func itemExistsAtIdxBefore() -> Bool { return (arr.valid(idx - 1) && arr[idx - 1]["hash"] == item["hash"]) } return itemAlreadyExistAtIdx() || itemExistsAtIdxBefore() } /** * New */ - static func existAtOrAfter(_ arr:[[String:String]],_ idx:Int, _ item:[String:String]) -> Bool { - func itemAlreadyExistAtIdx()->Bool {return (arr.valid(idx) && arr[idx]["hash"] == item["hash"]) } - func itemExistsAtIdxAfter()->Bool {return (arr.valid(idx+1) && arr[idx+1]["hash"] == item["hash"])} + static func existAtOrAfter(_ arr: [[String: String]], _ idx: Int, _ item: [String: String]) -> Bool { + func itemAlreadyExistAtIdx() -> Bool {return (arr.valid(idx) && arr[idx]["hash"] == item["hash"]) } + func itemExistsAtIdxAfter() -> Bool {return (arr.valid(idx + 1) && arr[idx + 1]["hash"] == item["hash"])} return itemAlreadyExistAtIdx() || itemExistsAtIdxAfter() } } //this makes CommitDB unwrappable (XML->CommitDB) -extension CommitDP:UnWrappable{ - static func unWrap(_ xml:XML) -> T? { +extension CommitDP: UnWrappable{ + static func unWrap(_ xml: XML) -> T? { //Swift.print("xml.xmlString.count: " + "\(xml.xmlString.count)") - let items:[[String:String]?] = unWrap(xml, "items") + let items:[[String: String]?] = unWrap(xml, "items") //let prevCommits:[Int:String] = unWrap(xml,"prevCommits") return CommitDP(items.flatMap{$0}/*,prevCommits*/) as? T/*flatMap is used to remove any nil values*/ } diff --git a/Sources/GitSyncMac/library/Config.swift b/Sources/GitSyncMac/library/Config.swift index 1197fd9ef..e3218e065 100644 --- a/Sources/GitSyncMac/library/Config.swift +++ b/Sources/GitSyncMac/library/Config.swift @@ -6,22 +6,22 @@ import Foundation enum Config { enum Bundle{ /*The root of the asset bundle*/ - static let assets:String = FilePathParser.resourcePath + "/assets.bundle/"//rename to user maybe? - static let styles:String = FilePathParser.resourcePath + "/styles.bundle/" - static let repo:String = {/*Stores the repo details*/ + static let assets: String = FilePathParser.resourcePath + "/assets.bundle/"//rename to user maybe? + static let styles: String = FilePathParser.resourcePath + "/styles.bundle/" + static let repo: String = {/*Stores the repo details*/ return assets + (Config.release == .dev ? "user/dev/" : "user/pub/") + "repos.xml" }() - static let structure:String = assets + "structure.json"/*UI structure of the app*/ - static let prefsURL:String = {/*The app prefs*/ + static let structure: String = assets + "structure.json"/*UI structure of the app*/ + static let prefsURL: String = {/*The app prefs*/ return assets + (Config.release == .dev ? "user/dev/" : "user/pub/") + "prefs.xml" }() - static let commitCacheURL:String = {/*Cache.swift uses this url*/ + static let commitCacheURL: String = {/*Cache.swift uses this url*/ return assets + (Config.release == .dev ? "user/dev/" : "user/pub/") + "sortedcommits.xml" }() - static let commitCountsURL:String = { + static let commitCountsURL: String = { return assets + (Config.release == .dev ? "user/dev/" : "user/pub/") + "commitCounts.json" }() } - enum ReleaseType {case dev,pub} - static let release:ReleaseType = .dev/*Toggle between development and public release*/ + enum ReleaseType { case dev, pub } + static let release: ReleaseType = .dev/*Toggle between development and public release*/ } diff --git a/Sources/GitSyncMac/library/Proxy.swift b/Sources/GitSyncMac/library/Proxy.swift index 7a8b5d431..f25139801 100644 --- a/Sources/GitSyncMac/library/Proxy.swift +++ b/Sources/GitSyncMac/library/Proxy.swift @@ -9,7 +9,7 @@ class Proxy { /** * New */ - static var styleTestView:StyleTestView? { + static var styleTestView: StyleTestView? { do { return try getStyleTestView() } catch let error as NSError { @@ -20,9 +20,9 @@ class Proxy { /** * New */ - private static func getStyleTestView() throws -> StyleTestView{ - guard let win:NSWindow = WinParser.focusedWindow() ?? NSApp.windows[safe:0] else {throw ProxyError.windowNotAvailable} - guard let styleTestView = win.contentView as? StyleTestView else {throw ProxyError.styleTestViewNotAvailable} + private static func getStyleTestView() throws -> StyleTestView { + guard let win: NSWindow = WinParser.focusedWindow() ?? NSApp.windows[safe: 0] else { throw ProxyError.windowNotAvailable } + guard let styleTestView = win.contentView as? StyleTestView else { throw ProxyError.styleTestViewNotAvailable } return styleTestView } } diff --git a/Sources/GitSyncMac/library/repo/RepoItem+Extensions.swift b/Sources/GitSyncMac/library/repo/RepoItem+Extensions.swift index f01bb0765..7bb69562e 100644 --- a/Sources/GitSyncMac/library/repo/RepoItem+Extensions.swift +++ b/Sources/GitSyncMac/library/repo/RepoItem+Extensions.swift @@ -4,24 +4,24 @@ import Foundation * Accessors */ extension RepoItem{ - var localPath:String {get {return local} set{local = newValue}} - var remotePath:String {get {return remote} set{remote = newValue}} + var localPath: String { get { return local } set { local = newValue } } + var remotePath: String { get { return remote } set { remote = newValue } } } -/** +/** * Parsers */ extension RepoItem{ /** * Converts GitRepo to RepoItem */ - var gitRepo:GitRepo { + var gitRepo: GitRepo { return GitRepo.gitRepo(self.local, remotePath, self.branch) } /** * Converts GitRepo to RepoItem */ - static func repoItem(_ gitRepo:GitRepo) -> RepoItem { + static func repoItem(_ gitRepo: GitRepo) -> RepoItem { var repoItem = RepoItem() repoItem.local = gitRepo.localPath repoItem.remote = "https://" + gitRepo.remotePath @@ -36,8 +36,8 @@ extension RepoItem{ /** * Basic */ - static func repoItem(local:String,branch:String,title:String,remote:String = "") -> RepoItem{ - var repoItem:RepoItem = RepoItem() + static func repoItem(local: String, branch: String, title: String, remote: String = "") -> RepoItem { + var repoItem: RepoItem = RepoItem() repoItem.local = local repoItem.branch = branch repoItem.title = title @@ -47,8 +47,8 @@ extension RepoItem{ /** * DummyData */ - static var dummyData:RepoItem { - return RepoItem.repoItem(local: "user file path",branch: "master",title: "Element iOS") + static var dummyData: RepoItem { + return RepoItem.repoItem(local: "user file path", branch: "master", title: "Element iOS") } } @@ -59,7 +59,7 @@ extension RepoItem{ extension RepoItem{ subscript(key: String) -> T? { get { - switch key{ + switch key { case "local": return local as? T case "branch": return branch as? T case "title": return title as? T @@ -73,7 +73,7 @@ extension RepoItem{ } } set { - switch key{ + switch key { case "local": local = newValue as! String //⚠️️ use if assert first case "branch": branch = newValue as! String case "title": title = newValue as! String @@ -88,4 +88,3 @@ extension RepoItem{ } } } - diff --git a/Sources/GitSyncMac/library/repo/RepoItem+Key.swift b/Sources/GitSyncMac/library/repo/RepoItem+Key.swift index ad01e6dbf..111d58529 100644 --- a/Sources/GitSyncMac/library/repo/RepoItem+Key.swift +++ b/Sources/GitSyncMac/library/repo/RepoItem+Key.swift @@ -1,15 +1,7 @@ import Foundation extension RepoItem { - enum Key{ - static let title = "title" - static let local = "local" - static let remote = "remote" - static let branch = "branch" - static let auto = "auto" - static let message = "message" - static let active = "active" - static let template = "template" - static let notification = "notification" + enum Key: String { + case title, local, remote, branch, auto, message, active, template, notification } } diff --git a/Sources/GitSyncMac/library/repo/RepoItem.swift b/Sources/GitSyncMac/library/repo/RepoItem.swift index e0d522a82..02128daae 100644 --- a/Sources/GitSyncMac/library/repo/RepoItem.swift +++ b/Sources/GitSyncMac/library/repo/RepoItem.swift @@ -1,19 +1,19 @@ import Foundation /** - * TODO: ⚠️️ rename to RepoData - * TODO: ⚠️️ Needs a unique identifier value + * Fixme: ⚠️️ rename to RepoData + * Fixme: ⚠️️ Needs a unique identifier value */ struct RepoItem { - var local:String/*Local path*/ - var branch:String/*Repo branch, Master is default*/ - var title:String/*The title displayed in the app*/ - var active:Bool/*Active means that auto and pull will sync the repo*/ - var remote:String/*Remote path to repository*/ - var message:Bool/*Auto-created commit message*///TODO: ⚠️️ rename - var auto:Bool/*Automatically syncs on an interval*///TODO: ⚠️️ rename to interval? - var template:String/*template message for commitmessages*/ - var notification:Bool/*toggle Notifications per repo*/ + var local: String/*Local path*/ + var branch: String/*Repo branch, Master is default*/ + var title: String/*The title displayed in the app*/ + var active: Bool/*Active means that auto and pull will sync the repo*/ + var remote: String/*Remote path to repository*/ + var message: Bool/*Auto-created commit message*///TODO: ⚠️️ rename + var auto: Bool/*Automatically syncs on an interval*///TODO: ⚠️️ rename to interval? + var template: String/*template message for commitmessages*/ + var notification: Bool/*toggle Notifications per repo*/ init(){/*Default RepoItem*/ self.local = ""/*Local path*/ self.branch = ""/*Repo branch, Master is default*/ diff --git a/Sources/GitSyncMac/library/repo/utils/RepoFolderType.swift b/Sources/GitSyncMac/library/repo/utils/RepoFolderType.swift index ee3ff44e2..7bcab0444 100644 --- a/Sources/GitSyncMac/library/repo/utils/RepoFolderType.swift +++ b/Sources/GitSyncMac/library/repo/utils/RepoFolderType.swift @@ -1,7 +1,6 @@ import Foundation -enum RepoFolderType:String{ - case isOpen = "isOpen" - case hasChildren = "hasChildren" +enum RepoFolderType: String{ + case isOpen, hasChildren } //move this to Key inside RepoItem diff --git a/Sources/GitSyncMac/library/repo/utils/RepoItemUtils.swift b/Sources/GitSyncMac/library/repo/utils/RepoItemUtils.swift index 8a1a0eee7..af8d4ffb8 100644 --- a/Sources/GitSyncMac/library/repo/utils/RepoItemUtils.swift +++ b/Sources/GitSyncMac/library/repo/utils/RepoItemUtils.swift @@ -7,20 +7,20 @@ import Foundation class RepoUtils { /** * Returns a flat Array of RepoItems derived from a nested xml Structure (also skips folders) - * NOTE: parent override child for every key in overrideKeys - * We want parent folders to override all its children. - * ⚠️️ You need to check if the local path is still avilable. FileASserter.exists, or else you might get strange bugs using the Git lib, and prompt the user to correct the path + * - NOTE: parent override child for every key in overrideKeys + * - Note: We want parent folders to override all its children. + * - Note: ⚠️️ You need to check if the local path is still avilable. FileASserter.exists, or else you might get strange bugs using the Git lib, and prompt the user to correct the path */ - static var repoListFlattenedOverridden:[RepoItem]{ + static var repoListFlattenedOverridden: [RepoItem] { // Swift.print("repoListFlattenedOverridden") - let repoXML:XML = RepoView.treeDP.tree.xml/*📝 - FilePath*/ - let arr:[Any] = XMLParser.arr(repoXML)//convert xml to multidimensional array + let repoXML: XML = RepoView.treeDP.tree.xml /*📝 - FilePath*/ + let arr: [Any] = XMLParser.arr(repoXML)//convert xml to multidimensional array // Swift.print("arr: " + "\(arr)") - let overrideKeys:[String] = [RepoItem.Key.active,/*RepoType.autoSyncInterval,RepoType.download,RepoType.fileChange,*/RepoItem.Key.auto/*,RepoType.upload*/]/*These are the keys to the values that should be overridden*/ - let overriders:[String] = [RepoFolderType.isOpen.rawValue,RepoFolderType.hasChildren.rawValue] - let flatArr:[[String:String]] = Utils.recursiveFlattened(arr,overrideKeys,overriders) - let repoListSansFolders:[RepoItem] = Utils.sansFolders(list:flatArr, mustNotContain:overriders)//remove folders - let activeRepoList = repoListSansFolders.filter{$0.active}/*filter out inActive*/ + let overrideKeys: [String] = [RepoItem.Key.active,/*RepoType.autoSyncInterval,RepoType.download,RepoType.fileChange,*/RepoItem.Key.auto/*,RepoType.upload*/]/*These are the keys to the values that should be overridden*/ + let overriders: [String] = [RepoFolderType.isOpen.rawValue,RepoFolderType.hasChildren.rawValue] + let flatArr: [[String: String]] = Utils.recursiveFlattened(arr,overrideKeys,overriders) + let repoListSansFolders: [RepoItem] = Utils.sansFolders(list:flatArr, mustNotContain:overriders)//remove folders + let activeRepoList = repoListSansFolders.filter { $0.active } /*filter out inActive*/ // activeRepoList.forEach{ // Swift.print("$0.title: " + "\($0.title)") // } @@ -28,13 +28,13 @@ class RepoUtils { } /** * Conforms repoItem data and returns a RepoItem that can be used with git - * TODO: ⚠️️ if the interval values is not set, then use default values - * TODO: ⚠️️ test if the full/partly file path still works? + * - TODO: ⚠️️ if the interval values is not set, then use default values + * - TODO: ⚠️️ test if the full/partly file path still works? */ - static func repoItem(dict:[String:String]) -> RepoItem{ + static func repoItem(dict: [String: String]) -> RepoItem { //Swift.print("dict: " + "\(dict)") - var repoItem:RepoItem = RepoItem() - let localPath:String = dict[RepoItem.Key.local]! //this is the path to the local repository (we need to be in this path to execute git commands on this repo) + var repoItem: RepoItem = RepoItem() + let localPath: String = dict[RepoItem.Key.local]! //this is the path to the local repository (we need to be in this path to execute git commands on this repo) //localPath = ShellUtils.run("echo " + StringModifier.wrapWith(localPath,"'") + " | sed 's/ /\\\\ /g'")//--Shell doesnt handle file paths with space chars very well. So all space chars are replaced with a backslash and space, so that shell can read the paths. repoItem.local = localPath repoItem.branch = dict[RepoItem.Key.branch]! @@ -45,7 +45,7 @@ class RepoUtils { repoItem.notification = dict[RepoItem.Key.notification]?.bool ?? false //Swift.print("dict[RepoType.active.rawValue]!: " + "\(dict[RepoType.active.rawValue]!)") repoItem.active = dict[RepoItem.Key.active]!.bool - let remotePath:String = dict[RepoItem.Key.remote]! + let remotePath: String = dict[RepoItem.Key.remote]! //remotePath = RegExp.replace(remotePath,"^https://.+$","")//support for partial and full url, strip away the https://, since this will be added later //print(remotePath) repoItem.remote = remotePath @@ -53,40 +53,40 @@ class RepoUtils { } /** * Returns an RepoItem for PARAM: xml at PARAM: idx - * PARAM: idx: matrixIndex - * TODO: ⚠️️ Should return optional + * - PARAM: idx: matrixIndex + * - TODO: ⚠️️ Should return optional */ static func repoItem(xml:XML,idx:[Int]) -> RepoItem{ - if let child:XML = XMLParser.childAt(xml, idx){ - let dict:[String:String] = child.attribs + if let child: XML = XMLParser.childAt(xml, idx){ + let dict: [String: String] = child.attribs let repoItem = self.repoItem(dict: dict) return repoItem - };fatalError("no child at idx: \(idx)") + }; fatalError("no child at idx: \(idx)") } } private class Utils{ /** * Recursive flatMap with parent overriding abilities - * NOTE: this also lets parents override the values in some keys in children - * INPUT: [[["color": "blue", "value": "003300", "title": "John"], [[["color": "orange", "value": "001122", "title": "Ben"]]]]] - * OUTPUT: [["color": "blue", "value": "003300", "title": "John"], ["color": "blue", "value": "001122", "title": "Ben"]] - * PARAM: overriders: only let items with either of these be able to override (aka folders) - * PARAM: overrideKeys: override these key value pairs. If non exist then make new - * TODO: ⚠️️ use throws to give better error description? + * - NOTE: this also lets parents override the values in some keys in children + * - INPUT: [[["color": "blue", "value": "003300", "title": "John"], [[["color": "orange", "value": "001122", "title": "Ben"]]]]] + * - OUTPUT: [["color": "blue", "value": "003300", "title": "John"], ["color": "blue", "value": "001122", "title": "Ben"]] + * - PARAM: overriders: only let items with either of these be able to override (aka folders) + * - PARAM: overrideKeys: override these key value pairs. If non exist then make new + * - TODO: ⚠️️ use throws to give better error description? */ - static func recursiveFlattened(_ arr:[Any], _ overrideKeys:[String], _ overriders:[String],_ parent:[String:String]? = nil) -> [T]{ - var result:[T] = [] - var parent:[String:String]? = parent + static func recursiveFlattened(_ arr: [Any], _ overrideKeys: [String], _ overriders: [String], _ parent: [String:String]? = nil) -> [T] { + var result: [T] = [] + var parent: [String:String]? = parent arr.forEach{ if $0 is AnyArray {/*array*/ - let a:[Any] = $0 as! [Any] + let a: [Any] = $0 as! [Any] result += recursiveFlattened(a,overrideKeys,overriders,parent) }else{/*item*/ - guard var dict:[String:String] = $0 as? [String:String] else {fatalError("err")} + guard var dict: [String:String] = $0 as? [String:String] else {fatalError("err")} if let parent = parent { overrideKeys.forEach{ if let value = parent[$0] { - let val:Bool = String(value).bool + let val: Bool = String(value).bool if !val {/*only disable overrides*/ dict.updateValue(value,forKey:$0)//creates new key,value pair if non exists } @@ -104,8 +104,8 @@ private class Utils{ /** * Compiles array with tuples and filter out folder related stuff */ - static func sansFolders(list:[[String:String]], mustNotContain:[String])->[RepoItem]{ - let repoList:[RepoItem] = list.filter{ + static func sansFolders(list: [[String: String]], mustNotContain: [String]) -> [RepoItem] { + let repoList: [RepoItem] = list.filter{ !$0.contains(mustNotContain) && $0.hasKey(RepoItem.Key.active) && $0[RepoItem.Key.active]!.bool/*skips folders, and active must be true*/ }.map{/*create array of tuples*/ // Swift.print("$0: " + "\($0)") @@ -121,16 +121,16 @@ private class Utils{ * TODO: Redesign the flattening, utilize the tree */ /* - + DEPREACATE this, we use repoListFlattenedOverridden now - + static var repoListFlattened:[RepoItem] { let repoXML:XML = RepoView.treeDP.tree.xml/*📝 - FilePath*/ let arr:[Any] = XMLParser.arr(repoXML)//convert xml to multidimensional array let flatArr:[[String:String]] = arr.recursiveFlatmap() //flatArr.forEach{Swift.print("$0: " + "\($0)")} let repoList:[RepoItem] = Utils.filterFolders(flatArr,[RepoFolderType.isOpen.rawValue,RepoFolderType.hasChildren.rawValue])//Swift.print("repoList.count: " + "\(repoList.count)") - + let activeRepoList = repoList.filter{$0.active}/*filter out inActive*/ activeRepoList.forEach{Swift.print("$0.title: " + "\($0.title)")} return activeRepoList @@ -140,9 +140,9 @@ private class Utils{ * Returns dupe free flattened repo list */ /* - + //TODO: ⚠️️ possibly remove this, its not used, removing dups is cool but we sort of need to sync all repos - + private static var repoListFlattenedDupeFree:[RepoItem]{ let repoList:[RepoItem] = RepoUtils.repoListFlattened//.filter{$0.title == "GitSync"}//👈 filter enables you to test one item at the time return repoList.removeDups({$0.remote == $1.remote && $0.branch == $1.branch})/*remove dups that have the same remote and branch. */ diff --git a/Sources/GitSyncMac/library/utils/Cache.swift b/Sources/GitSyncMac/library/utils/Cache.swift index 7bb36969b..12ba85bd0 100644 --- a/Sources/GitSyncMac/library/utils/Cache.swift +++ b/Sources/GitSyncMac/library/utils/Cache.swift @@ -5,11 +5,11 @@ class Cache{ /** * Read commits from disk (xml) */ - static func read()->CommitDP{ - let url:String = Config.Bundle.commitCacheURL.tildePath + static func read() -> CommitDP{ + let url: String = Config.Bundle.commitCacheURL.tildePath let xml = FileParser.xml(url) //Swift.print("xml.XMLString: " + "\(xml.XMLString)") - let commitDP:CommitDP? = CommitDP.unWrap(xml) + let commitDP: CommitDP? = CommitDP.unWrap(xml) //Swift.print("Printing sortedArr after unwrap: ") //commitDB.sortedArr.forEach{Swift.print($0.sortableDate)} return commitDP! @@ -19,11 +19,10 @@ class Cache{ */ static func write(_ commitDP:CommitDP){ //Swift.print("💾 write begin") - let xml:XML = Reflect.toXML(commitDP)/*Reflection*/ + let xml: XML = Reflect.toXML(commitDP)/*Reflection*/ //Swift.print(xml.xmlString) let contentToWriteToDisk = XMLParser.prettyString(xml)//xml.xmlString _ = FileModifier.write(Config.Bundle.commitCacheURL.tildePath, contentToWriteToDisk) //Swift.print("💾 write end") } } - diff --git a/Sources/GitSyncMac/library/utils/auto/AutoSync+Extensions.swift b/Sources/GitSyncMac/library/utils/auto/AutoSync+Extensions.swift index 02c872d93..1dadecda9 100644 --- a/Sources/GitSyncMac/library/utils/auto/AutoSync+Extensions.swift +++ b/Sources/GitSyncMac/library/utils/auto/AutoSync+Extensions.swift @@ -8,15 +8,15 @@ extension AutoSync{ * Syncs auto-message repos * NOTE: Also works if Nothing to sync */ - private func syncOtherRepos(){ + private func syncOtherRepos() { let group = DispatchGroup() otherRepos.forEach { repoItem in/*all the initCommit calls are non-waiting. */ group.enter() bg.async { - GitSync.initCommit(repoItem,nil,{group.leave()})/*🚪⬅️️ Enter the AutoSync process here, it's wrapped in a bg thread because hwne oush complets it jumps back on the main thread*/ + GitSync.initCommit(repoItem, nil) { group.leave() } /*🚪⬅️️ Enter the AutoSync process here, it's wrapped in a bg thread because hwne oush complets it jumps back on the main thread*/ } } - group.notify(queue: main){//It also fires when nothing left or entered + group.notify(queue: main) {//It also fires when nothing left or entered self.autoSyncComplete(self.repoVerifier.verifiedRepos)/*All commits and pushes was completed*/ } } @@ -27,9 +27,9 @@ extension AutoSync{ extension AutoSync{ /** * This is called when all repos are verified that they exist locally and remotly - * IMPORTANT: ⚠️️ messageRepoIterator.iterate() must be initiated or else iteration of other repos wont start + * - IMPORTANT: ⚠️️ messageRepoIterator.iterate() must be initiated or else iteration of other repos wont start */ - func onAllReposVerified(){ + func onAllReposVerified() { Swift.print("onAllReposVerified") messageRepoIterator.iterate()/*Iterate over repos with manual commit message*/ } @@ -41,20 +41,20 @@ extension AutoSync{ /** * Generates the repoList */ - static func createRepoList(isUserInitiated:Bool) -> [RepoItem]{ + static func createRepoList(isUserInitiated: Bool) -> [RepoItem]{ let repoList = RepoUtils.repoListFlattenedOverridden/*Get the latest repo list*/ // Swift.print("repoList.count: " + "\(repoList.count)") // repoList.forEach{ // Swift.print("$0: " + "\($0)") // } - return isUserInitiated ? repoList : repoList.filter{$0.auto}/*if interval initiated then only target repos that have interval set to true*/ + return isUserInitiated ? repoList : repoList.filter { $0.auto }/*if interval initiated then only target repos that have interval set to true*/ } /** * Generates the MessageRepoIterator */ - func createMessageRepoIterator(verifiedRepos:[RepoItem]) -> MessageRepoIterator{ - let messageRepos:[RepoItem] = verifiedRepos.filter{$0.message}/*repos that have manual commit message*/ + func createMessageRepoIterator(verifiedRepos: [RepoItem]) -> MessageRepoIterator { + let messageRepos: [RepoItem] = verifiedRepos.filter { $0.message }/*repos that have manual commit message*/ // Swift.print("messageRepos.count: " + "\(messageRepos.count)") - return .init(array:messageRepos,onComplete:syncOtherRepos) + return .init(array: messageRepos, onComplete: syncOtherRepos) } } diff --git a/Sources/GitSyncMac/library/utils/auto/AutoSync.swift b/Sources/GitSyncMac/library/utils/auto/AutoSync.swift index ce5f9d290..600861921 100644 --- a/Sources/GitSyncMac/library/utils/auto/AutoSync.swift +++ b/Sources/GitSyncMac/library/utils/auto/AutoSync.swift @@ -4,21 +4,21 @@ import Foundation * Takes care of staging, commiting, Pulling, pushing etc */ class AutoSync { - typealias AutoSyncCompleted = ([RepoItem])->Void - - let repoList:[RepoItem]/*All repos*/ - lazy var otherRepos = repoVerifier.verifiedRepos.filter{!$0.message}/*"Verified" and "auto message" repos*/ - lazy var repoVerifier = RepoVerifier.init(array:repoList,onComplete:onAllReposVerified)/*Step.1*/ - lazy var messageRepoIterator:MessageRepoIterator = createMessageRepoIterator(verifiedRepos:repoVerifier.verifiedRepos)/*Step.2*/ - let autoSyncComplete:AutoSyncCompleted/*When the AutoSync completes this is fired*/ + typealias AutoSyncCompleted = ([RepoItem]) -> Void + + let repoList: [RepoItem]/*All repos*/ + lazy var otherRepos = repoVerifier.verifiedRepos.filter { !$0.message }/*"Verified" and "auto message" repos*/ + lazy var repoVerifier: RepoVerifier = .init(array: repoList, onComplete: onAllReposVerified)/*Step.1*/ + lazy var messageRepoIterator: MessageRepoIterator = createMessageRepoIterator(verifiedRepos: repoVerifier.verifiedRepos)/*Step.2*/ + let autoSyncComplete: AutoSyncCompleted/*When the AutoSync completes this is fired*/ /** * The GitSync automation algo (Basically Commits and pushes) * PARAM: isUserInitiated: if interval initiated then only target repos that have interval set to true */ - init(isUserInitiated:Bool, onComplete:@escaping AutoSyncCompleted) { + init(isUserInitiated: Bool, onComplete:@escaping AutoSyncCompleted) { Swift.print("AutoSync isUserInitiated: \(isUserInitiated)") self.autoSyncComplete = onComplete - self.repoList = AutoSync.createRepoList(isUserInitiated:isUserInitiated) + self.repoList = AutoSync.createRepoList(isUserInitiated: isUserInitiated) Swift.print("self.repoList.count: " + "\(self.repoList.count)") repoVerifier.iterate() } diff --git a/Sources/GitSyncMac/library/utils/auto/utils/iterator/MessageRepoIterator.swift b/Sources/GitSyncMac/library/utils/auto/utils/iterator/MessageRepoIterator.swift index 4a31fbaa6..4567e5fbd 100644 --- a/Sources/GitSyncMac/library/utils/auto/utils/iterator/MessageRepoIterator.swift +++ b/Sources/GitSyncMac/library/utils/auto/utils/iterator/MessageRepoIterator.swift @@ -1,25 +1,25 @@ import Foundation @testable import Utils -class MessageRepoIterator:ArrayIterator { - typealias Completed = ()->Void +class MessageRepoIterator: ArrayIterator { + typealias Completed = () -> Void var complete:Completed - init(array: Array,onComplete:@escaping Completed) { + init(array: Array, onComplete:@escaping Completed) { self.complete = onComplete super.init(array: array) } /** * New */ - func iterate(){ + func iterate() { if hasNext() { // Swift.print("iterator.hasNext") - let repoItem:RepoItem = next() + let repoItem: RepoItem = next() // Swift.print("repoItem: " + "\(repoItem)") - if var commitMessage:CommitMessage = CommitMessageUtils.generateCommitMessage(repoItem.local) {/*if no commit msg is generated, then no commit is needed*/ + if var commitMessage: CommitMessage = CommitMessageUtils.generateCommitMessage(repoItem.local) {/*if no commit msg is generated, then no commit is needed*/ // Swift.print("has commit message") - if !repoItem.template.isEmpty {commitMessage.title = repoItem.template}//add template as title if it exists - Nav.setView(.dialog(.commit(repoItem,commitMessage,{self.iterate()})))/*this view eventually calls initCommit*/ + if !repoItem.template.isEmpty { commitMessage.title = repoItem.template }//add template as title if it exists + Nav.setView(.dialog(.commit(repoItem, commitMessage, { self.iterate() })))/*this view eventually calls initCommit*/ }else { // Swift.print("has no commit message") MergeUtils.manualMerge(repoItem){/*nothing to commit but check if remote has updates*/ @@ -32,10 +32,9 @@ class MessageRepoIterator:ArrayIterator { complete() } } - } extension MessageRepoIterator{ - var isEmpty:Bool {return self.collection.isEmpty} + var isEmpty: Bool { return self.collection.isEmpty } } diff --git a/Sources/GitSyncMac/library/utils/auto/utils/iterator/RepoVerifier.swift b/Sources/GitSyncMac/library/utils/auto/utils/iterator/RepoVerifier.swift index 740f1c7ba..6b6859984 100644 --- a/Sources/GitSyncMac/library/utils/auto/utils/iterator/RepoVerifier.swift +++ b/Sources/GitSyncMac/library/utils/auto/utils/iterator/RepoVerifier.swift @@ -3,11 +3,11 @@ import Foundation /** * Verifies if git project exists locally, prompts a wizard if doesn't exist */ -class RepoVerifier:ArrayIterator{ - typealias AllCompleted = ()->Void - let onAllComplete:AllCompleted - var verifiedRepos:[RepoItem] = [] - init(array: Array, onComplete:@escaping AllCompleted) { +class RepoVerifier: ArrayIterator { + typealias AllCompleted = () -> Void + let onAllComplete: AllCompleted + var verifiedRepos: [RepoItem] = [] + init(array: [T], onComplete:@escaping AllCompleted) { self.onAllComplete = onComplete super.init(array: array) } @@ -24,21 +24,21 @@ class RepoVerifier:ArrayIterator{ /** * Works as a onComplete handler, to facilitate canceling verification in "auto init dialog" */ - func verify(repoItem:RepoItem,verified:Bool){ - if verified {verifiedRepos.append(repoItem)} + func verify(repoItem: RepoItem, verified: Bool){ + if verified { verifiedRepos.append(repoItem) } iterate() } /** * NOTE: verifies if a repo exists locally, if not a wizard initiated */ - private func verifyGitProject(_ repoItem:RepoItem){ + private func verifyGitProject(_ repoItem: RepoItem) { // Swift.print("verifyGitProject") let conflict = AutoInitConflict.init(repoItem) if conflict.areRemotesEqual {/*No need to init AutoInit dialog*/ verify(repoItem: repoItem, verified: true) }else{ main.async{/*Jump on the main thread*/ - Nav.setView(.dialog(.autoInit(conflict,self.verify))) + Nav.setView(.dialog(.autoInit(conflict, self.verify))) } } } diff --git a/Sources/GitSyncMac/library/utils/refresh/Refresh+Extensions.swift b/Sources/GitSyncMac/library/utils/refresh/Refresh+Extensions.swift index df3813ba9..de1799efc 100644 --- a/Sources/GitSyncMac/library/utils/refresh/Refresh+Extensions.swift +++ b/Sources/GitSyncMac/library/utils/refresh/Refresh+Extensions.swift @@ -2,16 +2,16 @@ import Foundation @testable import Utils extension Refresh{ - typealias RefreshReposComplete = ()->Void - typealias RefreshRepoComplete = ()->Void - typealias CommitItemsComplete = (_ results:[String])->Void - typealias CommitCountComplete = (_ commitCount:Int)->Void + typealias RefreshReposComplete = () -> Void + typealias RefreshRepoComplete = () -> Void + typealias CommitItemsComplete = (_ results: [String]) -> Void + typealias CommitCountComplete = (_ commitCount: Int) -> Void /** * Adds commit items to CommitDB if they are newer than the oldest commit in CommitDB * Retrieve the commit log items for this repo with the range specified */ - func refreshRepo(_ repo:RepoItem,_ onRefreshRepoComplete:@escaping RefreshRepoComplete){ - Refresh.commitCount(dp,repo){ commitCount in/*once these completes then do result, you do not want to wait until calling refreshRepo*/ + func refreshRepo(_ repo: RepoItem, _ onRefreshRepoComplete:@escaping RefreshRepoComplete) { + Refresh.commitCount(dp, repo) { commitCount in/*once these completes then do result, you do not want to wait until calling refreshRepo*/ Refresh.commitItems(repo.local, commitCount) { results in //🚧0~100 Git calls/*creates an array raw commit item logs, from repo*/ results.forEach { result in if !result.isEmpty {/*resulting string must have characters*/ @@ -37,9 +37,9 @@ extension Refresh{ group.enter() bg.async { if !dp.items.isEmpty { - let lastDate:Int = dp.items.last!["sortableDate"]!.int/*the last date is always the furthest distant date 19:59,19:15,19:00 etc*/ - let gitTime:String = GitDateUtils.gitTime(lastDate.string)/*converts descending date to git time*/ - let rangeCount:Int = GitUtils.commitCount(repo.local, after: gitTime).int//🚧1 Git call /*Finds the num of commits from now until */ + let lastDate: Int = dp.items.last!["sortableDate"]!.int/*the last date is always the furthest distant date 19:59,19:15,19:00 etc*/ + let gitTime: String = GitDateUtils.gitTime(lastDate.string)/*converts descending date to git time*/ + let rangeCount: Int = GitUtils.commitCount(repo.local, after: gitTime).int//🚧1 Git call /*Finds the num of commits from now until */ commitCount = min(rangeCount,100)/*force the value to be no more than max allowed*/ }else {//< 100 commitCount = 100//You need to top up dp with 100 if dp.count = 0, ⚠️️ this works because later this value is cliped to max of repo.commits.count @@ -53,13 +53,13 @@ extension Refresh{ } /** * Basically creates an array of commit data from the latest commit until limit (limit:3 returns the 3 last commits) - * Returns an array of commitItems at PARAM: localPath and limited with PARAM: max - * PARAM: limit = max Items Allowed per repo + * - Returns an array of commitItems at PARAM: localPath and limited with PARAM: max + * - PARAM: limit = max Items Allowed per repo */ - static private func commitItems(_ localPath:String,_ limit:Int, _ onComplete:@escaping CommitItemsComplete) { - var results:[String] = Array(repeating: "", count:limit)//basically creates an array with many empty strings + static private func commitItems(_ localPath: String, _ limit: Int, _ onComplete:@escaping CommitItemsComplete) { + var results: [String] = Array(repeating: "", count: limit)//basically creates an array with many empty strings let group = DispatchGroup() - let formating:String = "--pretty=format:Hash:%h%nAuthor:%an%nDate:%ci%nSubject:%s%nBody:%b".encode()!//"-3 --oneline"// + let formating: String = "--pretty=format:Hash:%h%nAuthor:%an%nDate:%ci%nSubject:%s%nBody:%b".encode()!//"-3 --oneline"// // totalCommitCount += limit for i in 0..Element{ - switch view{ + private static func getView(_ view: ViewType, _ parentView: Element) -> Element { + switch view { case .main(let viewType):/*Main*/ switch viewType { case .commit: @@ -49,13 +48,12 @@ class Nav { case .detail(let viewType):/*Detail*/ switch viewType { case .commit(let commitData):/*CommitDetail*/ - let view:CommitDetailView = parentView.addSubView(CommitDetailView()) + let view: CommitDetailView = parentView.addSubView(CommitDetailView()) view.setCommitData(commitData)/*Updates the UI elements with the selected commit item*/ return view case .repo(let idx3d):/*RepoDetail*/ RepoView.selectedListItemIndex = idx3d - - let view:RepoDetailView = parentView.addSubView(RepoDetailView()) + let view: RepoDetailView = parentView.addSubView(RepoDetailView()) view.setRepoData() return view } @@ -76,7 +74,7 @@ class Nav { case .autoInit(let autoInitConflict,let onComplete): let view = AutoInitView() parentView.addSubview(view) - view.setData(autoInitConflict,onComplete) + view.setData(autoInitConflict, onComplete) return view } } diff --git a/Sources/GitSyncMac/manager/NavExtensions.swift b/Sources/GitSyncMac/manager/NavExtensions.swift index b2ce6df61..ce882cced 100644 --- a/Sources/GitSyncMac/manager/NavExtensions.swift +++ b/Sources/GitSyncMac/manager/NavExtensions.swift @@ -1,19 +1,16 @@ import Foundation -@testable import Utils +@testable import Utils extension Nav{ - enum ViewType{ + enum ViewType { /*Main*/ - enum Main:String{ - case commit = "commit" - case repo = "repo" - case prefs = "prefs" - case stats = "stats" + enum Main: String{ + case commit, repo, prefs, stats } case main(Main) /*Detail*/ enum Detail{ - case commit([String:String]) + case commit([String: String]) case repo([Int]) } case detail(Detail) @@ -21,8 +18,8 @@ extension Nav{ case dialog(Dialog) enum Dialog{ case conflict(MergeConflict) - case commit(RepoItem,CommitMessage,CommitDialogView.Completed) - case autoInit(AutoInitConflict,AutoInitView.Complete) + case commit(RepoItem, CommitMessage, CommitDialogView.Completed) + case autoInit(AutoInitConflict, AutoInitView.Complete) } } } diff --git a/Sources/GitSyncMac/manager/NotificationManager.swift b/Sources/GitSyncMac/manager/NotificationManager.swift index 341799498..935233541 100644 --- a/Sources/GitSyncMac/manager/NotificationManager.swift +++ b/Sources/GitSyncMac/manager/NotificationManager.swift @@ -5,7 +5,7 @@ class NotificationManager { /** * Sends Message to NotificationCenter in MacOS about latest commit */ - static func notifyUser(message commitMessage:CommitMessage,repo repoItem:RepoItem){ + static func notifyUser(message commitMessage: CommitMessage, repo repoItem: RepoItem){ guard PrefsView.prefs.notification else { return }//don't send notification if it's globally turned off let notification = NSUserNotification() notification.title = "\(repoItem.title)"//Committed in: diff --git a/Sources/GitSyncMac/menu/Menu.swift b/Sources/GitSyncMac/menu/Menu.swift index 49da605b6..3dde52fec 100644 --- a/Sources/GitSyncMac/menu/Menu.swift +++ b/Sources/GitSyncMac/menu/Menu.swift @@ -7,9 +7,9 @@ import Cocoa */ class Menu { init(){ - guard let mainMenu = NSApp.mainMenu else {fatalError("NSApp.mainMenu not accessible")} - while(mainMenu.items.count > 1){ - mainMenu.removeItem(at: mainMenu.items.count-1) + guard let mainMenu = NSApp.mainMenu else { fatalError("NSApp.mainMenu not accessible") } + while mainMenu.items.count > 1 { + mainMenu.removeItem(at: mainMenu.items.count - 1) } _ = mainMenu.addMenuItem(ViewMenu()) _ = CustomAboutMenu() diff --git a/Sources/GitSyncMac/menu/PrefsMenu.swift b/Sources/GitSyncMac/menu/PrefsMenu.swift index be4619638..d246fb05f 100644 --- a/Sources/GitSyncMac/menu/PrefsMenu.swift +++ b/Sources/GitSyncMac/menu/PrefsMenu.swift @@ -6,16 +6,16 @@ class PreferencesMenuItem:CustomMenuItem{ init() { super.init(CustomAboutMenu.preferences, ",") } - override func onSelect(event:AnyObject) { + override func onSelect(event: AnyObject) { Swift.print("PreferencesMenuItem.onSelect") //Proxy.windows.append(WinUtils.buildWin(PreferencesWin.self))/*open the prefs window*/ } /** * Return true if you want to enable the menu item, false will disable it */ - override func validateMenuItem(_ menuItem:NSMenuItem) -> Bool { + override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { //add assertion logic here return true } - required init(coder decoder:NSCoder) {fatalError("init(coder:) has not been implemented")} + required init(coder decoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } diff --git a/Sources/GitSyncMac/menu/view/View.swift b/Sources/GitSyncMac/menu/view/View.swift index 6dd07d8cc..2265ca642 100644 --- a/Sources/GitSyncMac/menu/view/View.swift +++ b/Sources/GitSyncMac/menu/view/View.swift @@ -2,79 +2,79 @@ import Cocoa @testable import Utils @testable import Element -class ViewMenu:CustomMenuItem { +class ViewMenu: CustomMenuItem { init(){ super.init("View", "") submenu = NSMenu(title: "View") _ = submenu?.addMenuItem(ToggleSideBarMenuItem()) _ = submenu?.addMenuItem(PagesMenu()) _ = submenu?.addMenuItem(ExportReposMenu("Export repos", "e")) - _ = submenu?.addMenuItem(ImportReposMenu("Import repos", "i")) + _ = submenu?.addMenuItem(ImportReposMenu("Import repos", "i")) } - override func onSelect(event sender: AnyObject){ + override func onSelect(event sender: AnyObject) { Swift.print("ViewMenu.onSelect() " + "\(sender)") } - required init(coder decoder:NSCoder) {fatalError("init(coder:) has not been implemented")} + required init(coder decoder:NSCoder) { fatalError("init(coder:) has not been implemented") } } -class ExportReposMenu:CustomMenuItem{ +class ExportReposMenu: CustomMenuItem { override func onSelect(event: AnyObject) { //grab the xml let xml = RepoView.treeDP.tree.xml //prompt the file viewer - let dialog:NSSavePanel = NSSavePanel.initialize(["xml"], "Export repos", true) + let dialog: NSSavePanel = NSSavePanel.initialize(["xml"], "Export repos", true) dialog.directoryURL = "~/Desktop/".tildePath.url let respons = dialog.runModal() - - if let url = dialog.url,respons == NSApplication.ModalResponse.OK{/*Make sure that a path was chosen*/ + + if let url = dialog.url, respons == NSApplication.ModalResponse.OK {/*Make sure that a path was chosen*/ _ = xml.xmlString.write(filePath:url.path.tildePath) } } } -class ImportReposMenu:CustomMenuItem{ +class ImportReposMenu: CustomMenuItem{ override func onSelect(event: AnyObject) { //grab the xml - + //prompt the file viewer - let dialog:NSOpenPanel = NSOpenPanel() + let dialog: NSOpenPanel = NSOpenPanel() dialog.directoryURL = "~/Desktop/".tildePath.url let respons = dialog.runModal() //let thePath:String? = dialog.url?.path /*Get the path to the file chosen in the NSOpenPanel*/ - + //TODO: use two guards on the bellow instead - - if let url = dialog.url,respons == NSApplication.ModalResponse.OK{/*Make sure that a path was chosen*/ + + if let url = dialog.url, respons == NSApplication.ModalResponse.OK {/*Make sure that a path was chosen*/ if let xml = url.path.tildePath.content?.xml{ RepoView._treeDP = TreeDP(xml) } } } } -class PagesMenu:CustomMenuItem{ - init(){ +class PagesMenu: CustomMenuItem { + init() { super.init("Pages", "") submenu = NSMenu(title: "Pages") - + _ = submenu?.addMenuItem(LogMenu( "Log", "l")) - _ = submenu?.addMenuItem(RepoMenu("Repos","r")) - _ = submenu?.addMenuItem(PrefsMenu("Prefs","s")) + _ = submenu?.addMenuItem(RepoMenu("Repos", "r")) + _ = submenu?.addMenuItem(PrefsMenu("Prefs", "s")) } - override func onSelect(event sender:AnyObject){ + override func onSelect(event sender: AnyObject) { Swift.print("PagesMenu.onSelect() " + "\(sender)") } - required init(coder decoder:NSCoder) {fatalError("init(coder:) has not been implemented")} + required init(coder decoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } -class LogMenu:CustomMenuItem{ +class LogMenu: CustomMenuItem{ override func onSelect(event: AnyObject) { Nav.setView(.main(.commit)) } } -class RepoMenu:CustomMenuItem{ +class RepoMenu: CustomMenuItem { override func onSelect(event: AnyObject) { Nav.setView(.main(.repo)) } } -class PrefsMenu:CustomMenuItem{ +class PrefsMenu: CustomMenuItem { override func onSelect(event: AnyObject) { Nav.setView(.main(.prefs)) } diff --git a/Sources/GitSyncMac/menu/view/items/ToggleSideBarMenuItem.swift b/Sources/GitSyncMac/menu/view/items/ToggleSideBarMenuItem.swift index 2c969add7..f8b41c5fa 100644 --- a/Sources/GitSyncMac/menu/view/items/ToggleSideBarMenuItem.swift +++ b/Sources/GitSyncMac/menu/view/items/ToggleSideBarMenuItem.swift @@ -2,8 +2,8 @@ import Cocoa @testable import Utils @testable import Element -class ToggleSideBarMenuItem:CustomMenuItem{ - init() {super.init("Show side bar", "m")} +class ToggleSideBarMenuItem: CustomMenuItem { + init() { super.init("Show side bar", "m") } override func onSelect(event:AnyObject) { Swift.print("ShowSideBarMenuItem.onSelect()") guard let styleTestView = Proxy.styleTestView else {return} @@ -13,11 +13,11 @@ class ToggleSideBarMenuItem:CustomMenuItem{ /** * Return true if you want to enable the menu item, false will disable it */ - override func validateMenuItem(_ menuItem:NSMenuItem) -> Bool { - guard let styleTestView = Proxy.styleTestView else {return false} + override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + guard let styleTestView = Proxy.styleTestView else { return false } self.title = styleTestView.leftBar.isLeftBarHidden ? "Show side bar" : "Hide side bar" Swift.print("validateMenuItem") return true } - required init(coder decoder: NSCoder) {fatalError("init(coder:) has not been implemented")} + required init(coder decoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } diff --git a/Sources/GitSyncMac/utils/GitSync.swift b/Sources/GitSyncMac/utils/GitSync.swift index b2eaee4bd..4404f7f88 100644 --- a/Sources/GitSyncMac/utils/GitSync.swift +++ b/Sources/GitSyncMac/utils/GitSync.swift @@ -2,59 +2,58 @@ import Foundation @testable import Utils class GitSync{ - typealias PushComplete = ()->Void + typealias PushComplete = () -> Void /** * Handles the process of making a commit for a single repository - * PARAM: idx: stores the idx of the repoItem in PARAM repoList which is needed in the onComplete to then start the push on the correct item + * - PARAM: idx: stores the idx of the repoItem in PARAM repoList which is needed in the onComplete to then start the push on the correct item */ - static func initCommit(_ repoItem:RepoItem, _ commitMessage:CommitMessage? = nil, _ onPushComplete:@escaping PushComplete){ - func doCommit(){ - _ = commit(repoItem,commitMessage)/*🌵 if there were no commits false will be returned*/ + static func initCommit(_ repoItem: RepoItem, _ commitMessage: CommitMessage? = nil, _ onPushComplete:@escaping PushComplete){ + func doCommit() { + _ = commit(repoItem, commitMessage)/*🌵 if there were no commits false will be returned*/ initPush(repoItem, onPushComplete)//push or check if you need to pull down changes and subsequently merge something } if let unMergedFiles = GitParser.unMergedFiles(repoItem.local).optional {/*🌵Asserts if there are unmerged paths that needs resolvment, aka remote changes that isnt in local*/ - MergeReslover.shared.resolveConflicts(repoItem, unMergedFiles){ + MergeReslover.shared.resolveConflicts(repoItem, unMergedFiles) { doCommit() } - }else{ + } else { doCommit() } } /** * Handles the process of making a push for a single repository (When a singular commit has competed this method is called) - * NOTE: We must always merge the remote branch into the local branch before we push our changes. - * NOTE: this method performs a "manual pull" on every interval - * TODO: ⚠️️ Contemplate implimenting a fetch call after the pull call, to update the status, whats the diff between git fetch and git remote update again? - * IMPORTANT: ⚠️️ this is called on a background thread + * - NOTE: We must always merge the remote branch into the local branch before we push our changes. + * - NOTE: this method performs a "manual pull" on every interval + * - TODO: ⚠️️ Contemplate implimenting a fetch call after the pull call, to update the status, whats the diff between git fetch and git remote update again? + * - IMPORTANT: ⚠️️ this is called on a background thread */ - private static func initPush(_ repoItem:RepoItem, _ onPushComplete:@escaping PushComplete){ + private static func initPush(_ repoItem: RepoItem, _ onPushComplete:@escaping PushComplete){ MergeUtils.manualMerge(repoItem){//🌵🌵🌵 commits, merges with promts, (this method also test if a merge is needed or not, and skips it if needed) let repo:GitRepo = repoItem.gitRepo let hasLocalCommits = GitAsserter.hasLocalCommits(repo.localPath, repoItem.branch)/*🌵🌵 TODO: maybe use GitAsserter's is_local_branch_ahead instead of this line*/ if hasLocalCommits { //only push if there are commits to be pushed, hence the has_commited flag, we check if there are commits to be pushed, so we dont uneccacerly push if there are no local commits to be pushed, we may set the commit interval and push interval differently so commits may stack up until its ready to be pushed, read more about this in the projects own FAQ - guard let keychainPassword:String = KeyChainParser.password("GitSyncApp") else{ fatalError("password not found")} + guard let keychainPassword: String = KeyChainParser.password("GitSyncApp") else { fatalError("password not found") } let key:GitKey = .init(PrefsView.prefs.login, keychainPassword) if PrefsView.prefs.login.isEmpty || keychainPassword.isEmpty {fatalError("need login and pass")} - _ = GitModifier.push(repo,key)/*🌵*/ + _ = GitModifier.push(repo, key)/*🌵*/ } {/*Swift.print("before call");*/onPushComplete()}() } } /** * This method generates a git status list,and asserts if a commit is due, and if so, compiles a commit message and then tries to commit - * Returns true if a commit was made, false if no commit was made or an error occured - * NOTE: checks git staus, then adds changes to the index, then compiles a commit message, then commits the changes, and is now ready for a push - * NOTE: only commits if there is something to commit - * TODO: ⚠️️ add branch parameter to this call - * NOTE: this a purly local method, does not need to communicate with remote servers etc.. + * - Returns true if a commit was made, false if no commit was made or an error occured + * - NOTE: checks git staus, then adds changes to the index, then compiles a commit message, then commits the changes, and is now ready for a push + * - NOTE: only commits if there is something to commit + * - TODO: ⚠️️ add branch parameter to this call + * - NOTE: this a purly local method, does not need to communicate with remote servers etc.. */ - static func commit(_ repoItem:RepoItem, _ commitMessage:CommitMessage? = nil)->Bool{ + static func commit(_ repoItem:RepoItem, _ commitMessage: CommitMessage? = nil)->Bool{ // Swift.print("commit: \(commitMessage)") - guard let msg:CommitMessage = commitMessage ?? CommitMessage.autoCommitMessage(repoItem: repoItem, commitMessage: commitMessage) else{return false}/*No commitMessage means no commit*/ - if repoItem.notification { NotificationManager.notifyUser(message: msg,repo: repoItem) } + guard let msg:CommitMessage = commitMessage ?? CommitMessage.autoCommitMessage(repoItem: repoItem, commitMessage: commitMessage) else { return false }/*No commitMessage means no commit*/ + if repoItem.notification { NotificationManager.notifyUser(message: msg, repo: repoItem) } // Swift.print("msg.title: " + "\(msg.title)") - _ = GitModifier.commit(repoItem.localPath, CommitMessage(msg.title,msg.description))//🌵 commit + _ = GitModifier.commit(repoItem.localPath, CommitMessage(msg.title, msg.description))//🌵 commit return true } } - diff --git a/Sources/GitSyncMac/utils/MergeReslover.swift b/Sources/GitSyncMac/utils/MergeReslover.swift index bbffdf32b..a8ceaaeef 100644 --- a/Sources/GitSyncMac/utils/MergeReslover.swift +++ b/Sources/GitSyncMac/utils/MergeReslover.swift @@ -3,17 +3,17 @@ import Foundation class MergeReslover { typealias AllComplete = () -> Void - var allComplete:AllComplete = {fatalError("No handler attached")} + var allComplete: AllComplete = { fatalError("No handler attached") } static let shared = MergeReslover() - var conflictCount:Int = 0 - var index:Int = 0//curConflictIndex - var unMergedFiles:[String] = [] - var repoItem:RepoItem? + var conflictCount: Int = 0 + var index: Int = 0//curConflictIndex + var unMergedFiles: [String] = [] + var repoItem: RepoItem? /** * Promts the user with a list of options to aid in resolving merge conflicts - * PARAM branch: the branch you tried to merge into + * - PARAM branch: the branch you tried to merge into */ - func resolveConflicts(_ repoItem:RepoItem, _ unMergedFiles:[String], _ allComplete:@escaping AllComplete){ + func resolveConflicts(_ repoItem: RepoItem, _ unMergedFiles: [String], _ allComplete:@escaping AllComplete) { // Swift.print("MergeReslover.resolveConflicts") self.allComplete = allComplete index = 0//reset @@ -25,34 +25,34 @@ class MergeReslover { /** * Iterate through the conflicts */ - func nextConflict(){ + func nextConflict() { Swift.print("nextConflict") - guard index < conflictCount else{//stop iteration if all conflicts are resolved + guard index < conflictCount else {//stop iteration if all conflicts are resolved Swift.print("allComplete") allComplete() return } // let lastSelectedAction:String = options.first! //you may want to make this a "property" to store the last item more permenantly - guard let repoItem = repoItem else{fatalError("error")} + guard let repoItem = repoItem else { fatalError("error") } // Swift.print("localRepoPath: " + "\(String(describing: repoItem.localPath))") // Swift.print("branch: " + "\(String(describing: repoItem.branch))") // Swift.print("lastSelectedAction: " + "\(lastSelectedAction)") // Swift.print("unMergedFile: " + "\(unMergedFiles[index])") - - let issue:String = "Conflict: Resolve merge conflict in"//Local file is older than the remote file - let file:String = "File: \(unMergedFiles[index])" - let repo:String = "Repository: \(repoItem.title)" - let mergeConflict = MergeConflict(issue:issue,file:file,repo:repo) - - main.async{ - Nav.setView(.dialog(.conflict(mergeConflict)))//promt user with list of options, title: Merge conflict in: unmerged_file + + let issue: String = "Conflict: Resolve merge conflict in"//Local file is older than the remote file + let file: String = "File: \(unMergedFiles[index])" + let repo: String = "Repository: \(repoItem.title)" + let mergeConflict = MergeConflict(issue: issue, file: file, repo: repo) + + main.async { + Nav.setView(.dialog(.conflict(mergeConflict))) // promt user with list of options, title: Merge conflict in: unmerged_file } //listWindow.addTarget(self, action: "Complete: ", forControlEvents: .complete) } - + /** * Handles the choice made in the merge conflict dialog - * TODO: test the open file clauses + * - TODO: test the open file clauses */ func processMergeStrategy(_ option:Option/*, _ unmergedFile:String, _ localRepoPath:String, _ branch:String, _ unmergedFiles:[String]*/){ Swift.print("MergeUtil.processMergeStrategy()") @@ -78,7 +78,6 @@ class MergeReslover { _ = GitModifier.checkOut(localRepoPath, branch, unmergedFile) } index += 1 - case Option.all(let allOption): switch allOption { case .local: @@ -92,24 +91,24 @@ class MergeReslover { _ = GitModifier.checkOut(localRepoPath, branch, "*") } index = conflictCount - + } - //after each iteration you have to commit, bring that into the fold + // after each iteration you have to commit, bring that into the fold Swift.print("before commit") _ = GitSync.commit(repoItem!)//🌵 It's best practice to always commit any uncommited files before you attempt to pull, add,commit if any files has an altered status Swift.print("after commit") nextConflict() - + } } extension MergeReslover{ enum Option{ - enum All{ - case local,remote,mix + enum All { + case local, remote, mix } - enum Singular{ - case local,remote,mix + enum Singular { + case local, remote, mix } case all(All) case singular(Singular) @@ -140,5 +139,3 @@ extension MergeReslover{ /*open all mixed versions*/ // _ = GitModifier.checkOut(localRepoPath, branch, "*") // FileUtils.openFiles([])/*localRepoPath,unmergedFiles*/ - - diff --git a/Sources/GitSyncMac/utils/MergeUtils.swift b/Sources/GitSyncMac/utils/MergeUtils.swift index 30737ffc7..f9a87f801 100644 --- a/Sources/GitSyncMac/utils/MergeUtils.swift +++ b/Sources/GitSyncMac/utils/MergeUtils.swift @@ -3,14 +3,14 @@ import Foundation /** * Utility methods for merging branches */ -struct MergeConflict{ - let issue:String,file:String,repo:String +struct MergeConflict { + let issue: String, file: String, repo: String } -extension MergeConflict{ - static let dummyData:MergeConflict = { - let issue:String = "Conflict: Local file is older than the remote file" - let file:String = "File: Element.swift" - let repo:String = "Repository: Element - iOS" +extension MergeConflict { + static let dummyData: MergeConflict = { + let issue: String = "Conflict: Local file is older than the remote file" + let file: String = "File: Element.swift" + let repo: String = "Repository: Element - iOS" return MergeConflict(issue: issue, file: file, repo: repo) }() } @@ -19,28 +19,28 @@ class MergeUtils{ typealias ManualMergeComplete = () -> Void /** * Manual merge - * NOTE: tries to merge a remote branch into a local branch - * NOTE: prompts the users if a merge conflicts occure - * TODO: we should use two branch params here since its entirly possible to merge from a different remote branch + * - NOTE: tries to merge a remote branch into a local branch + * - NOTE: prompts the users if a merge conflicts occure + * - TODO: we should use two branch params here since its entirly possible to merge from a different remote branch */ - static func manualMerge(_ repoItem:RepoItem, _ onManualMergeComplete:@escaping ManualMergeComplete){ + static func manualMerge(_ repoItem: RepoItem, _ onManualMergeComplete:@escaping ManualMergeComplete) { // Swift.print("🍊 MergeUtils.manualMerge()") - var hasUnMergedPaths:Bool { + var hasUnMergedPaths: Bool { return GitAsserter.hasUnMergedPaths(repoItem.localPath)//🌵 Asserts if there are unmerged paths that needs resolvment } - var hasManualPullReturnedError:Bool { + var hasManualPullReturnedError: Bool { return GitUtils.manualPull(repoItem.gitRepo)//🌵 Manual pull down files } - if hasUnMergedPaths || hasManualPullReturnedError{ + if hasUnMergedPaths || hasManualPullReturnedError { // Swift.print("has unmerged paths to resolve") - let unMergedFiles:[String] = GitParser.unMergedFiles(repoItem.localPath)//🌵 Compile a list of conflicting files somehow + let unMergedFiles: [String] = GitParser.unMergedFiles(repoItem.localPath)//🌵 Compile a list of conflicting files somehow MergeReslover.shared.resolveConflicts(repoItem, unMergedFiles){ //_ = GitSync.commit(repoItem.localPath)//🌵 It's best practice to always commit any uncommited files before you attempt to pull, add,commit if any files has an altered status onManualMergeComplete() }//🌵 Asserts if there are unmerged paths that needs resolvment }else { // Swift.print("MergeUtils.manualMerge() no resolvment needed") - onManualMergeComplete() + onManualMergeComplete() } } } diff --git a/Sources/GitSyncMac/utils/StatusUtils.swift b/Sources/GitSyncMac/utils/StatusUtils.swift index 777ba8d11..5e076fdce 100644 --- a/Sources/GitSyncMac/utils/StatusUtils.swift +++ b/Sources/GitSyncMac/utils/StatusUtils.swift @@ -6,14 +6,14 @@ import Foundation class StatusUtils{ /* * Returns a descriptive status list of the current git changes - * NOTE: You may use short status, but you must interpret the message if the state has an empty space infront of it + * - NOTE: You may use short status, but you must interpret the message if the state has an empty space infront of it */ - static func generateStatusList(_ localRepoPath:String)->[[String:String]]{ - let theStatus:String = GitParser.status(localRepoPath, "-s") /*the -s stands for short message, and returns a short version of the status message, the short stauslist is used because it is easier to parse than the long status list*/ + static func generateStatusList(_ localRepoPath: String) -> [[String: String]] { + let theStatus: String = GitParser.status(localRepoPath, "-s") /*the -s stands for short message, and returns a short version of the status message, the short stauslist is used because it is easier to parse than the long status list*/ // Swift.print("generateStatusList.theStatus: " + "\(theStatus)") - let theStatusList:[String] = StringParser.paragraphs(theStatus) /*store each line as items in a list*/ + let theStatusList: [String] = StringParser.paragraphs(theStatus) /*store each line as items in a list*/ // Swift.print("theStatusList: " + "\(theStatusList)") - guard !theStatusList.isEmpty else {return []}/*this is the status msg if there has happened nothing new since last, but also if you have commits that are ready for push to origin, aka nothing to commit, working directory clean*/ + guard !theStatusList.isEmpty else { return [] }/*this is the status msg if there has happened nothing new since last, but also if you have commits that are ready for push to origin, aka nothing to commit, working directory clean*/ // Swift.print("before transformed list") let transformedList = transformStatusList(theStatusList) // Swift.print("return transformed list") @@ -21,45 +21,45 @@ class StatusUtils{ } /* * Transforms the "compact git status list" by adding more context to each item (a list with acociative lists, aka records) - * Returns a list with records that contain staus type, file name and state - * NOTE: the short status msg format is like: "M" " M", "A", " A", "R", " R" etc - * NOTE: C = copied, U = updated but unmerged also exists - * NOTE: the space infront of the capetalized char indicates Changes not staged for commit: - * NOTE: Returns = renamed, M = modified, A = addedto index, D = deleted, ?? = untracked file - * NOTE: the state can be: "Changes not staged for commit" , "Untracked files" , "Changes to be committed" - * PARAM: theStatusList is a list with status messages like: {"?? test.txt"," M index.html","A home.html"} - * NOTE: can also be "UU" unmerged paths - * TODO: ⚠️️ Use functional programming on this method. - * TODO: ⚠️️ Improve the error checking in this class + * - Returns a list with records that contain staus type, file name and state + * - NOTE: the short status msg format is like: "M" " M", "A", " A", "R", " R" etc + * - NOTE: C = copied, U = updated but unmerged also exists + * - NOTE: the space infront of the capetalized char indicates Changes not staged for commit: + * - NOTE: Returns = renamed, M = modified, A = addedto index, D = deleted, ?? = untracked file + * - NOTE: the state can be: "Changes not staged for commit" , "Untracked files" , "Changes to be committed" + * - PARAM: theStatusList is a list with status messages like: {"?? test.txt"," M index.html","A home.html"} + * - NOTE: can also be "UU" unmerged paths + * - TODO: ⚠️️ Use functional programming on this method. + * - TODO: ⚠️️ Improve the error checking in this class */ - static func transformStatusList(_ theStatusList:[String])->[[String:String]]{ - var transformedList:[[String:String]] = [] - for theStatusItem:String in theStatusList { + static func transformStatusList(_ theStatusList: [String]) -> [[String: String]] { + var transformedList: [[String: String]] = [] + for theStatusItem: String in theStatusList { // Swift.print("theStatusItem: " + "\(theStatusItem)") - let matches:[NSTextCheckingResult] = RegExp.matches(theStatusItem, "^( )*([MARDUC?]{1,2}) (.+)$") //--returns 3 capturing groups, - let theStatusParts:NSTextCheckingResult = matches[0] - enum StatusParts:Int{ case first = 0, second , third, fourth} - let second:String = theStatusParts.range(at: StatusParts.second.rawValue).length > 0 ? RegExp.value(theStatusItem,theStatusParts,StatusParts.second.rawValue) : "" + let matches: [NSTextCheckingResult] = RegExp.matches(theStatusItem, "^( )*([MARDUC?]{1,2}) (.+)$") //--returns 3 capturing groups, + let theStatusParts: NSTextCheckingResult = matches[0] + enum StatusParts: Int { case first = 0, second , third, fourth } + let second: String = theStatusParts.range(at: StatusParts.second.rawValue).length > 0 ? RegExp.value(theStatusItem, theStatusParts, StatusParts.second.rawValue) : "" //Swift.print("second: " + "\(second)") - let third:String = RegExp.value(theStatusItem,theStatusParts,StatusParts.third.rawValue) + let third: String = RegExp.value(theStatusItem, theStatusParts, StatusParts.third.rawValue) //Swift.print("third: " + "\(third)") - let fourth:String = RegExp.value(theStatusItem,theStatusParts,StatusParts.fourth.rawValue) + let fourth: String = RegExp.value(theStatusItem, theStatusParts, StatusParts.fourth.rawValue) //Swift.print("fourth: " + "\(fourth)") //--log "length of theStatusParts: " & (length of theStatusParts) //--log theStatusParts - var statusItem:[String:String] = ["state":"", "cmd":"", "fileName":""] //--store the individual parts in an accociative - if (second == " ") { //--aka " M", remember that the second item is the first capturing group + var statusItem: [String: String] = ["state": "", "cmd": "", "fileName": ""] //--store the individual parts in an accociative + if second == " " { //--aka " M", remember that the second item is the first capturing group statusItem["cmd"] = third //--Changes not staged for commit: statusItem["state"] = "Changes not staged for commit" //-- you Pneed to add them - }else{ //-- Changes to be committed--aka "M " or "??" or "UU" + } else { //-- Changes to be committed--aka "M " or "??" or "UU" statusItem["cmd"] = third //--rename cmd to type //--log "cmd: " & cmd - if(statusItem["cmd"] == "??"){ + if statusItem["cmd"] == "??" { statusItem["state"] = "Untracked files" - }else if(statusItem["cmd"] == "UU") { //--Unmerged path + } else if statusItem["cmd"] == "UU" { //--Unmerged path //--log "Unmerged path" statusItem["state"] = "Unmerged path" - }else{ + } else { statusItem["state"] = "Changes to be committed" //--this is when the file is ready to be commited } } @@ -71,24 +71,24 @@ class StatusUtils{ } enum StatusType{ static let untrackedFiles = "Untracked files" - static let changesNotStagedForCommit = "Changes not staged for commit" - static let changestoBeCommitted = "Changes to be committed" - static let unmergedPath = "Unmerged path" + static let changesNotStagedForCommit = "Changes not staged for commit" + static let changestoBeCommitted = "Changes to be committed" + static let unmergedPath = "Unmerged path" } /** * Iterates over the status items and "git add" the item unless it's already added (aka "staged for commit") - * NOTE: if the status list is empty then there is nothing to process - * NOTE: even if a file is removed, its status needs to be added to the next commit - * TODO: ⚠️️ Squash some of the states together with if or or or etc.. + * - NOTE: if the status list is empty then there is nothing to process + * - NOTE: even if a file is removed, its status needs to be added to the next commit + * - TODO: ⚠️️ Squash some of the states together with if or or or etc.. */ - static func processStatusList(_ localRepoPath:String, _ statusList:[[String:String]]){ + static func processStatusList(_ localRepoPath: String, _ statusList: [[String: String]]) { // Swift.print("processStatusList.localRepoPath: " + "\(localRepoPath)") - let group:DispatchGroup = .init() - statusList.forEach{ (statusItem:[String:String]) in + let group: DispatchGroup = .init() + statusList.forEach{ (statusItem: [String: String]) in group.enter() // Swift.print("statusItem: " + "\(statusItem)") - let state:String = statusItem["state"]! - let fileName:String = statusItem["fileName"]! + let state: String = statusItem["state"]! + let fileName: String = statusItem["fileName"]! switch state { case StatusType.untrackedFiles: /*this is when there exists a new file*/ _ = GitModifier.add(localRepoPath, fileName) /*🌵 add the file to the next commit*/ diff --git a/Sources/GitSyncMac/utils/commit/CommitDescUtils.swift b/Sources/GitSyncMac/utils/commit/CommitDescUtils.swift index d60b7c3aa..67cc3f715 100644 --- a/Sources/GitSyncMac/utils/commit/CommitDescUtils.swift +++ b/Sources/GitSyncMac/utils/commit/CommitDescUtils.swift @@ -7,15 +7,15 @@ class CommitDescUtils{ /** * Returns a "Git Commit Message Description" derived from a "git status list" with "status items records" */ - class func sequenceDescription(_ statusList:[[String:String]])->String{ - var descText:String = "" - var modifiedItems:[[String:String]] = [] - var deletedItems:[[String:String]] = [] - var renamedItems:[[String:String]] = [] - var addedItems:[[String:String]] = [] - for statusItem:[String:String] in statusList{ - let cmd:String = statusItem["cmd"]! - switch GitCMD(rawValue:cmd){ + class func sequenceDescription(_ statusList: [[String: String]]) -> String{ + var descText: String = "" + var modifiedItems: [[String: String]] = [] + var deletedItems: [[String: String]] = [] + var renamedItems: [[String: String]] = [] + var addedItems: [[String: String]] = [] + for statusItem: [String: String] in statusList{ + let cmd: String = statusItem["cmd"]! + switch GitCMD(rawValue: cmd) { case .D?:deletedItems.append(statusItem) /*add a record to a list*/ case .R?:renamedItems.append(statusItem) /*add a record to a list*/ case .RM?:renamedItems.append(statusItem) /*add a record to a list*/ @@ -47,11 +47,11 @@ class CommitDescUtils{ /** * Returns a paragraph with a detailed description for Deleted, added and modified files */ - class func descriptionParagraph(_ theList:[[String:String]], prefix prefixText:String)->String{ + class func descriptionParagraph(_ theList: [[String: String]], prefix prefixText: String) -> String { if !theList.isEmpty { - var theSuffix:String = " file" + var theSuffix: String = " file" if theList.count > 1 { theSuffix += "s" }/*multiple*/ - let descText:String = prefixText + "\(theList.count)" + theSuffix + ":" + "\n" + let descText: String = prefixText + "\(theList.count)" + theSuffix + ":" + "\n" return theList.reduce(descText) { $0 + $1["fileName"]! + "\n" /*adds an extra line break at the end "paragraph like"*/ } + "\n" diff --git a/Sources/GitSyncMac/utils/commit/CommitMessage+Extensions.swift b/Sources/GitSyncMac/utils/commit/CommitMessage+Extensions.swift index 8d9487127..0cffdd86f 100644 --- a/Sources/GitSyncMac/utils/commit/CommitMessage+Extensions.swift +++ b/Sources/GitSyncMac/utils/commit/CommitMessage+Extensions.swift @@ -5,16 +5,16 @@ extension CommitMessage{ /** * New */ - init(statusList:[[String:String]]){ - let title:String = CommitMessageUtils.sequenceCommitMsgTitle(statusList) //sequence commit msg title for the commit - let desc:String = CommitDescUtils.sequenceDescription(statusList)//sequence commit msg description for the commit + init(statusList: [[String: String]]) { + let title: String = CommitMessageUtils.sequenceCommitMsgTitle(statusList) //sequence commit msg title for the commit + let desc: String = CommitDescUtils.sequenceDescription(statusList)//sequence commit msg description for the commit self.init(title, desc) } /** * New */ - static func autoCommitMessage(repoItem:RepoItem, commitMessage:CommitMessage?) -> CommitMessage?{ - var autoMessage:CommitMessage? = CommitMessageUtils.generateCommitMessage(repoItem.localPath) + static func autoCommitMessage(repoItem: RepoItem, commitMessage: CommitMessage?) -> CommitMessage?{ + var autoMessage: CommitMessage? = CommitMessageUtils.generateCommitMessage(repoItem.localPath) // Swift.print("repoItem.title: " + "\(repoItem.title)") // Swift.print("repoItem.template: " + "\(repoItem.template)") if autoMessage != nil, !repoItem.template.isEmpty { @@ -25,4 +25,3 @@ extension CommitMessage{ return autoMessage } } - diff --git a/Sources/GitSyncMac/utils/commit/CommitMessageUtils.swift b/Sources/GitSyncMac/utils/commit/CommitMessageUtils.swift index cdb1b20ca..531078183 100644 --- a/Sources/GitSyncMac/utils/commit/CommitMessageUtils.swift +++ b/Sources/GitSyncMac/utils/commit/CommitMessageUtils.swift @@ -8,25 +8,25 @@ class CommitMessageUtils{ * NOTE: C,I,R seems to never be triggered, COPIED,IGNORED,REMOVED, * NOTE: In place of Renamed, Git first deletes the file then says its untracked */ - static func sequenceCommitMsgTitle(_ statusList:[[String:String]])->String{ - var numOfNewFiles:Int = 0 - var numOfModifiedFiles:Int = 0 - var numOfDeletedFiles:Int = 0 - var numOfRenamedFiles:Int = 0 + static func sequenceCommitMsgTitle(_ statusList: [[String: String]]) -> String{ + var numOfNewFiles: Int = 0 + var numOfModifiedFiles: Int = 0 + var numOfDeletedFiles: Int = 0 + var numOfRenamedFiles: Int = 0 for statusItem in statusList{ let cmd = statusItem["cmd"]!/*TODO: ⚠️️ rename to type or status_type*/ - switch GitCMD(rawValue:cmd){ - case .M?:numOfModifiedFiles += 1 - case .MM?:numOfModifiedFiles += 1/*new and experimental*/ - case .MD?:numOfDeletedFiles += 1/*new and experimental*/ - case .D?:numOfDeletedFiles += 1 - case .A?:numOfNewFiles += 1 - case .AA?:numOfNewFiles += 1 - case .AM?:numOfNewFiles += 1 - case .AD?:numOfNewFiles += 1 + switch GitCMD(rawValue: cmd) { + case .M?: numOfModifiedFiles += 1 + case .MM?: numOfModifiedFiles += 1/*new and experimental*/ + case .MD?: numOfDeletedFiles += 1/*new and experimental*/ + case .D?: numOfDeletedFiles += 1 + case .A?: numOfNewFiles += 1 + case .AA?: numOfNewFiles += 1 + case .AM?: numOfNewFiles += 1 + case .AD?: numOfNewFiles += 1 case .R?: numOfRenamedFiles += 1/*This command seems to never be triggered in git*/ - case .RM?:numOfRenamedFiles += 1/*new and experimental*/ - case .RD?:numOfRenamedFiles += 1/*beta*/ + case .RM?: numOfRenamedFiles += 1/*new and experimental*/ + case .RD?: numOfRenamedFiles += 1/*beta*/ case .QQ?: numOfNewFiles += 1/*untracked files*/ case .UU?: numOfModifiedFiles += 1/*unmerged files*/ case .UA?: numOfNewFiles += 1/*unmerged files*/ @@ -37,7 +37,7 @@ class CommitMessageUtils{ break; } } - var commitMessage:String = "" + var commitMessage: String = "" if numOfNewFiles > 0 { commitMessage += "New files added: " + "\(numOfNewFiles)" } @@ -58,12 +58,12 @@ class CommitMessageUtils{ /** * Auto commit msg */ - static func generateCommitMessage(_ localRepoPath:String) -> CommitMessage? { + static func generateCommitMessage(_ localRepoPath: String) -> CommitMessage? { // Swift.print("generateCommitMessage.localRepoPath: " + "\(localRepoPath)") - let statusList:[[String:String]] = StatusUtils.generateStatusList(localRepoPath)//get current status + let statusList: [[String: String]] = StatusUtils.generateStatusList(localRepoPath)//get current status // Swift.print("statusList: " + "\(statusList.count)") // Swift.print("before") - guard !statusList.isEmpty else {return nil}/*nothing to add or commit,break the flow since there is nothing to commit or process*/ + guard !statusList.isEmpty else { return nil }/*nothing to add or commit,break the flow since there is nothing to commit or process*/ /*there is something to add or commit*/ // Swift.print("before processStatusList") StatusUtils.processStatusList(localRepoPath, statusList)/*process current status by adding files, now the status has changed, some files may have disapared, some files now have status as renamed that prev was set for adding and del*/ diff --git a/Sources/GitSyncMac/utils/commit/GitCMD.swift b/Sources/GitSyncMac/utils/commit/GitCMD.swift index 6ce2ac325..26e5c31bd 100644 --- a/Sources/GitSyncMac/utils/commit/GitCMD.swift +++ b/Sources/GitSyncMac/utils/commit/GitCMD.swift @@ -2,31 +2,31 @@ import Foundation /** * Utility methods for parsing the the "git status message" - * TODO: Sometimes RM shows up, figure out what that does - * NOTE: ' ' = unmodified, M = modified,A = added,D = deleted,R = renamed,C = copied,U = updated but unmerged - * IMPORTANT ⚠️️ sequenceCommitMsgTitle and sequenceDescription also uses this enum + * - TODO: Sometimes RM shows up, figure out what that does + * - NOTE: ' ' = unmodified, M = modified,A = added,D = deleted,R = renamed,C = copied,U = updated but unmerged + * - IMPORTANT ⚠️️ sequenceCommitMsgTitle and sequenceDescription also uses this enum */ -enum GitCMD:String{ - case M = "M"/*When a file is modified*/ - case D = "D"/*When a file is deleted*/ - case A = "A"/*When a file is added*/ - case R = "R"/*When a file is renamed,*/ - case C = "C"/*When a file is copied,beta*/ - case RD = "RD"/*BETA*/ - case DU = "DU"/*unmerged, deleted by us*/ - case DD = "DD"/*unmerged, both deleted*/ - case DM = "DM"/*deleted from index*/ - case AA = "AA"/*unmerged, both added*/ - case AU = "AU"/*unmerged, added by us*/ - case AM = "AM"/*Beta, needs description, probably file added with two parents*/ - case AD = "AD" //beta - case MM = "MM"/*There are two Ms in your example because it's a merge commit with two parents*/ - case MD = "MD"//beta - case RM = "RM"/*When a file is renamed, new and experimental*/ +enum GitCMD: String{ + case M /*When a file is modified*/ + case D /*When a file is deleted*/ + case A /*When a file is added*/ + case R /*When a file is renamed,*/ + case C /*When a file is copied,beta*/ + case RD /*BETA*/ + case DU /*unmerged, deleted by us*/ + case DD /*unmerged, both deleted*/ + case DM /*deleted from index*/ + case AA /*unmerged, both added*/ + case AU /*unmerged, added by us*/ + case AM /*Beta, needs description, probably file added with two parents*/ + case AD //beta + case MM /*There are two Ms in your example because it's a merge commit with two parents*/ + case MD //beta + case RM /*When a file is renamed, new and experimental*/ + case UU /*unmerged, both modified*/ + case UD /*unmerged, deleted by them*/ + case UA /*unmerged, added by them*/ + case CM /*copied, modified? beta*/ case QQ = "??"/*untracked*/ case EE = "!!"/*ignored*/ - case UU = "UU"/*unmerged, both modified*/ - case UD = "UD"/*unmerged, deleted by them*/ - case UA = "UA"/*unmerged, added by them*/ - case CM = "CM"/*copied, modified? beta*/ } diff --git a/Sources/GitSyncMac/window/view/dialog/MergeConflictView.swift b/Sources/GitSyncMac/window/view/dialog/MergeConflictView.swift index 383565285..e8210fee1 100644 --- a/Sources/GitSyncMac/window/view/dialog/MergeConflictView.swift +++ b/Sources/GitSyncMac/window/view/dialog/MergeConflictView.swift @@ -3,19 +3,19 @@ import Foundation @testable import Element /** * MERGE Conflict dialog view - * TODO: ⚠️️ Make the review buttons as a clickable text in the keep radiobuttons. - * TODO: ⚠️️ Inline the radiobuttons: Keep: (x) local, () remote, () both - * TODO: ⚠️️ Remove the cancel button and enable the close button again + * - TODO: ⚠️️ Make the review buttons as a clickable text in the keep radiobuttons. + * - TODO: ⚠️️ Inline the radiobuttons: Keep: (x) local, () remote, () both + * - TODO: ⚠️️ Remove the cancel button and enable the close button again */ -class MergeConflictView:Element,UnFoldable,Closable{ - lazy var radioButtonGroup:SelectGroup = {//TODO: ⚠️️ move this into an extension +class MergeConflictView:Element, UnFoldable, Closable{ + lazy var radioButtonGroup: SelectGroup = {//TODO: ⚠️️ move this into an extension let buttons:[RadioButton] = ElementParser.children(self) let group = SelectGroup(buttons,buttons.first) group.addHandler(type: SelectGroupEvent.change, self.onSelectGroupChange) return group }() - lazy var checkBoxButtonGroup:CheckGroup = {//TODO: ⚠️️ move this into an extension - let buttons:[CheckBoxButton] = ElementParser.children(self) + lazy var checkBoxButtonGroup: CheckGroup = {//TODO: ⚠️️ move this into an extension + let buttons: [CheckBoxButton] = ElementParser.children(self) let group = CheckGroup(buttons) group.addHandler(type: SelectGroupEvent.change, self.onCheckGroupChange) return group @@ -23,27 +23,27 @@ class MergeConflictView:Element,UnFoldable,Closable{ override func resolveSkin() { Swift.print("MergeConflictView.resolveSkin()") super.resolveSkin() - Unfold.unFold(fileURL: Config.Bundle.structure,path: "mergeConflictView",parent: self) + Unfold.unFold(fileURL: Config.Bundle.structure, path: "mergeConflictView", parent: self) Swift.print("unfold completed") - - self.apply([Key.issue,Text.Key.text], "Conflict: Local file is older than the remote file") - self.apply([Key.file,Text.Key.text], "File: AppDelegate.swift") - self.apply([Key.repo,Text.Key.text], "Repository: Element - iOS") - + + self.apply([Key.issue, Text.Key.text], "Conflict: Local file is older than the remote file") + self.apply([Key.file, Text.Key.text], "File: AppDelegate.swift") + self.apply([Key.repo, Text.Key.text], "Repository: Element - iOS") + _ = radioButtonGroup } - override func onEvent(_ event:Event) { + override func onEvent(_ event: Event) { if event.assert(.upInside, id: "ok"){ onOKButtonClick() }else if event.assert(.upInside, id: "cancel"){ fatalError("not yet supported") }/*else if event.assert(SelectEvent.select){ - + }*/ } } extension MergeConflictView{ - func setData(_ mergeConflict:MergeConflict){ + func setData(_ mergeConflict:MergeConflict) { Swift.print("MergeConflictView.setData") self.apply([Key.issue], mergeConflict.issue) self.apply([Key.file], mergeConflict.file) @@ -59,10 +59,10 @@ extension MergeConflictView{ static let applyAllConflicts = "applyAllConflicts" static let applyAllRepos = "applyAllRepos" } - func onSelectGroupChange(event:Event){ + func onSelectGroupChange(event: Event){ Swift.print("onSelectGroupChange event.selectable: " + "\(event)") } - func onCheckGroupChange(event:Event){/*this is the event handler*/ + func onCheckGroupChange(event: Event){/*this is the event handler*/ Swift.print("onSelectGroupChange event.selectable: " + "\(event)") } /** @@ -70,40 +70,32 @@ extension MergeConflictView{ */ func onOKButtonClick(){ Swift.print("onOKButtonClick") - - - - let selectedRadioButtonId:String = (radioButtonGroup.selected as? ElementKind)?.id ?? {fatalError("error")}() + let selectedRadioButtonId: String = (radioButtonGroup.selected as? ElementKind)?.id ?? {fatalError("error")}() Swift.print("selectedRadioButtonId: " + "\(String(describing: selectedRadioButtonId))") - - guard let isApplyAllConflictsChecked:Bool = try? self.retrieve([Key.applyAllConflicts]) else {fatalError("error")} + guard let isApplyAllConflictsChecked: Bool = try? self.retrieve([Key.applyAllConflicts]) else {fatalError("error")} Swift.print("isApplyAllConflictsChecked: " + "\(String(describing: isApplyAllConflictsChecked))") - guard let isApplyApplyAllReposChecked:Bool = try? self.retrieve([Key.applyAllRepos]) else {fatalError("error")} + guard let isApplyApplyAllReposChecked: Bool = try? self.retrieve([Key.applyAllRepos]) else {fatalError("error")} Swift.print("isApplyApplyAllReposChecked: " + "\(String(describing: isApplyApplyAllReposChecked))") - - defer{ let strategy = MergeConflictView.strategy(isApplyAllConflictsChecked,selectedRadioButtonId) MergeReslover.shared.processMergeStrategy(strategy) } - - if let curPrompt = Proxy.styleTestView?.currentPrompt {curPrompt.removeFromSuperview()}//remove promptView from window - + } } extension MergeConflictView{ /** * */ - static func strategy(_ applyToAll:Bool,_ id:String) -> MergeReslover.Option{ + static func strategy(_ applyToAll: Bool,_ id: String) -> MergeReslover.Option{ let option:MergeReslover.Option = { if applyToAll { return MergeReslover.Option.all( { if id == Key.keepLocal { return .local - }else if id == Key.keepRemote{ + }else if id == Key.keepRemote { return .remote }else{//Key.keepMixed return .mix @@ -122,7 +114,7 @@ extension MergeConflictView{ } }() ) - + } }() return option diff --git a/Sources/GitSyncMac/window/view/dialog/autoinit/AutoInitView.swift b/Sources/GitSyncMac/window/view/dialog/autoinit/AutoInitView.swift index 6f0a3a04b..45028caf3 100644 --- a/Sources/GitSyncMac/window/view/dialog/autoinit/AutoInitView.swift +++ b/Sources/GitSyncMac/window/view/dialog/autoinit/AutoInitView.swift @@ -3,27 +3,25 @@ import Cocoa @testable import Element class AutoInitView:Element,UnFoldable,Closable{ - //TODO:⚠️️ rename to AutoInitDialog - var verifiedRepos:[RepoItem]? - typealias Complete = (RepoItem,Bool) -> Void - var onComplete:Complete = {(_,_) in fatalError("Please assign handler")} - var conflict:AutoInitConflict? + var verifiedRepos: [RepoItem]? + typealias Complete = (RepoItem, Bool) -> Void + var onComplete:Complete = { (_,_) in fatalError("Please assign handler") } + var conflict: AutoInitConflict? override func resolveSkin() { Swift.print("AutoInitView.resolveSkin()") super.resolveSkin() - Unfold.unFold(fileURL: Config.Bundle.structure, path: "autoInitView",parent: self) + Unfold.unFold(fileURL: Config.Bundle.structure, path: "autoInitView", parent: self) Swift.print("AutoInitView.unfold completed") } override func onEvent(_ event:Event) { if event.assert(.upInside, id: "ok"){ onOKButtonClick() - }else if event.assert(.upInside, id: "cancel"){ + } else if event.assert(.upInside, id: "cancel"){ //fatalError("not yet supported: \(conflict!.repoItem)") self.removeFromSuperview() - guard let conflict = conflict else {fatalError("err")} - onComplete(conflict.repoItem,false)/*All done return to caller*/ + guard let conflict = conflict else { fatalError("err") } + onComplete(conflict.repoItem, false)/*All done return to caller*/ } } } - diff --git a/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitConflict.swift b/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitConflict.swift index 94e26d118..565348558 100644 --- a/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitConflict.swift +++ b/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitConflict.swift @@ -3,30 +3,29 @@ import Foundation /** * Note: We don't use a struct here because struct doesn't do lazy var */ -class AutoInitConflict{ - let repoItem:RepoItem - lazy var pathExists:Bool = { +class AutoInitConflict { + let repoItem: RepoItem + lazy var pathExists: Bool = { return FileAsserter.exists(self.repoItem.localPath.tildePath) }() - lazy var hasPathContent:Bool = { - guard self.pathExists else{return false} + lazy var hasPathContent: Bool = { + guard self.pathExists else { return false } return FileAsserter.hasContent(self.repoItem.localPath.tildePath) }() - lazy var isGitRepo:Bool = { + lazy var isGitRepo: Bool = { guard self.pathExists else {return false} return GitAsserter.isGitRepo(self.repoItem.localPath.tildePath) }() - lazy var areRemotesEqual:Bool = { - guard self.isGitRepo else{return false} + lazy var areRemotesEqual: Bool = { + guard self.isGitRepo else { return false } // Swift.print("curRemotePath: " + ">\(self.curRemotePath)<") // Swift.print("repoItem.remotePath: " + ">\(self.repoItem.remotePath)<") return self.curRemotePath == self.repoItem.remotePath }() - lazy var curRemotePath:String = { + lazy var curRemotePath: String = { return GitParser.originUrl(self.repoItem.localPath) }() - - init(_ repoItem:RepoItem){ + init(_ repoItem: RepoItem){ self.repoItem = repoItem } } diff --git a/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitConflictUtils.swift b/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitConflictUtils.swift index b8f42d050..803fb6721 100644 --- a/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitConflictUtils.swift +++ b/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitConflictUtils.swift @@ -2,46 +2,46 @@ import Foundation @testable import Utils class AutoInitConflictUtils { - typealias State = (pathExists:Bool,hasPathContent:Bool,isGitRepo:Bool,areRemotesEqual:Bool) - typealias TextData = (issue:String,proposal:String) + typealias State = (pathExists: Bool, hasPathContent: Bool, isGitRepo: Bool, areRemotesEqual: Bool) + typealias TextData = (issue: String, proposal: String) /** * Creates the text for the AutoInitPrompt */ - static func text(_ conflict:AutoInitConflict)->TextData{//TODO: ⚠️️ Move to AutoInitUtils + static func text(_ conflict: AutoInitConflict) -> TextData { // TODO: ⚠️️ Move to AutoInitUtils Swift.print("AutoInitConflict.text") let repoItem = conflict.repoItem - var issue:String = "" - var proposal:String = "" - let state:State = (conflict.pathExists,conflict.hasPathContent,conflict.isGitRepo,conflict.areRemotesEqual) + var issue: String = "" + var proposal: String = "" + let state: State = (conflict.pathExists, conflict.hasPathContent, conflict.isGitRepo, conflict.areRemotesEqual) Swift.print("state: " + "\(state)") switch state {/*pathExists,hasPathContent,isGitRepo,areRemotesEqual*/ - case (true,true,true,false): + case (true, true, true, false): issue = "There is already a git project in the folder: \(repoItem.local) with a different remote URL" proposal = "Do you want to replace the remote URL with the new URL?" - case (true,true,false,_): + case (true, true, false,_): issue = "The folder \(repoItem.localPath) is not a git repo but there are pre-exisiting files" proposal = "Do you want to delete the repo, download from remote?" - case (true,false,_,_): + case (true, false,_,_): issue = "The folder in path: " + "\(repoItem.localPath) is empty" proposal = "Do you want to download the remote git repository into this path?" - case (false,_,_,_): + case (false, _, _, _): issue = "The path \(repoItem.localPath) doesn't exist" proposal = "Do you want to download the remote git repository into this path?"//\(repoItem.remotePath) default: fatalError("Has no strategy for this scenario \(state)") } - return (issue,proposal) + return (issue, proposal) } /** - * NOTE: after this you often want to : MergeUtils.manualMerge(repoItem,{}) - * TODO: ⚠️️ Make this try do design pattern + * - NOTE: after this you often want to : MergeUtils.manualMerge(repoItem,{}) + * - TODO: ⚠️️ Make this try do design pattern */ - static func process(_ conflict:AutoInitConflict){//TODO: ⚠️️ Move to AutoInitUtils + static func process(_ conflict: AutoInitConflict){//TODO: ⚠️️ Move to AutoInitUtils let state:State = (conflict.pathExists,conflict.hasPathContent,conflict.isGitRepo,conflict.areRemotesEqual) let repoItem = conflict.repoItem Swift.print("AutoInitConflic.process() state: \(state)") switch state {/*pathExists,hasPathContent,isGitRepo,areRemotesEqual*/ - case (true,true,true,false): + case (true, true, true, false): Swift.print("a") // let gitURL:String = (repoItem.localPath+"/.git").tildePath // Swift.print("gitURL: " + "\(gitURL)") @@ -53,30 +53,30 @@ class AutoInitConflictUtils { // _ = GitModifier.attachRemoteRepo(repoItem.localPath,repoItem.remotePath)//--add new remote origin //git remote set-url origin https://github.com/username/repo _ = GitModifier.replaceRemote(localRepoPath: repoItem.localPath.tildePath, replacementRepoRemote: repoItem.remotePath) - case (true,true,false,_): + case (true, true, false, _): Swift.print("b") // GitUtils.manualClone(repoItem.localPath.tildePath, repoItem.remotePath, repoItem.branch) FileModifier.delete(repoItem.localPath.tildePath) FileModifier.createDir(repoItem.localPath.tildePath) _ = GitModifier.clone(repoItem.remotePath, repoItem.localPath.tildePath) - //Continue here: + //Continue here: //Try the process manually in appdelegate, something isnt working - //sync normally then use appdelegate after + //sync normally then use appdelegate after //never mind, just delete the path and use normal clone 👈 // _ = GitModifier.initialize(repoItem.localPath) // _ = GitModifier.attachRemoteRepo(repoItem.localPath,repoItem.remotePath)//--add new remote origin - case (true,false,_,_): + case (true, false, _, _): Swift.print("c") - + // FileModifier.delete(repoItem.localPath.tildePath) - - let status = GitModifier.clone(repoItem.remotePath,repoItem.localPath.tildePath) + + let status = GitModifier.clone(repoItem.remotePath, repoItem.localPath.tildePath) Swift.print("status: " + "\(status)") - case (false,_,_,_): + case (false, _, _, _): Swift.print("d") // FileModifier.delete(repoItem.localPath.tildePath) FileModifier.createDir(repoItem.localPath.tildePath) - let result = GitModifier.clone(repoItem.remotePath,repoItem.localPath.tildePath)//--this will create the folders if they dont exist, even nested + let result = GitModifier.clone(repoItem.remotePath, repoItem.localPath.tildePath)//--this will create the folders if they dont exist, even nested Swift.print("result: " + "\(result)") default: fatalError("Has no strategy for this scenario: \(state) ") diff --git a/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitDialog+Extensions.swift b/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitDialog+Extensions.swift index 6edc45e06..83ed1b9a5 100644 --- a/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitDialog+Extensions.swift +++ b/Sources/GitSyncMac/window/view/dialog/autoinit/utils/AutoInitDialog+Extensions.swift @@ -18,9 +18,9 @@ extension AutoInitView{ */ func onOKButtonClick(){ Swift.print("onOKButtonClick") - guard let conflict = conflict else {fatalError("err")} + guard let conflict = conflict else { fatalError("err") } AutoInitConflictUtils.process(conflict)//executes the git commands - onComplete(conflict.repoItem,true)/*All done return to caller*/ + onComplete(conflict.repoItem, true)/*All done return to caller*/ self.removeFromSuperview() } } diff --git a/Sources/GitSyncMac/window/view/dialog/commit/CommitDialogView+Extensions.swift b/Sources/GitSyncMac/window/view/dialog/commit/CommitDialogView+Extensions.swift index 34f7f8e1b..149fb73ee 100644 --- a/Sources/GitSyncMac/window/view/dialog/commit/CommitDialogView+Extensions.swift +++ b/Sources/GitSyncMac/window/view/dialog/commit/CommitDialogView+Extensions.swift @@ -3,8 +3,8 @@ import Cocoa @testable import Element extension CommitDialogView{ - typealias Completed = ()->Void - enum Key{ + typealias Completed = () -> Void + enum Key { static let repo = "repo" static let title = "title" static let desc = "desc" @@ -12,27 +12,26 @@ extension CommitDialogView{ /** * New */ - func setData(_ repoItem:RepoItem, _ commitMessage:CommitMessage, _ onCommitDialogComplete:@escaping Completed){ + func setData(_ repoItem:RepoItem, _ commitMessage: CommitMessage, _ onCommitDialogComplete:@escaping Completed){ self.onCommitDialogComplete = onCommitDialogComplete self.repoItem = repoItem - self.apply([Key.repo,TextInput.Key.inputText],repoItem.title) - self.apply([Key.title,TextInput.Key.inputText],commitMessage.title) - self.apply([Key.desc,TextInput.Key.inputText],commitMessage.description) + self.apply([Key.repo, TextInput.Key.inputText], repoItem.title) + self.apply([Key.title, TextInput.Key.inputText], commitMessage.title) + self.apply([Key.desc, TextInput.Key.inputText], commitMessage.description) } /** * EventHandler for the okButton click event */ - func onOKButtonClick(){ - guard let repoItem = self.repoItem else {fatalError("repoItem must be available")} + func onOKButtonClick() { + guard let repoItem = self.repoItem else { fatalError("repoItem must be available") } //⚠️️ use do catch on the bellow - guard let title:String = try? self.retrieve([Key.title,TextInput.Key.inputText]) else { fatalError("error - must have title") } - guard let desc:String = try? self.retrieve([Key.desc,TextInput.Key.inputText]) else {fatalError("error - must have description")} - let commitMessage = CommitMessage(title,desc) - + guard let title: String = try? self.retrieve([Key.title, TextInput.Key.inputText]) else { fatalError("error - must have title") } + guard let desc: String = try? self.retrieve([Key.desc, TextInput.Key.inputText]) else { fatalError("error - must have description") } + let commitMessage = CommitMessage(title, desc) bg.async { - GitSync.initCommit(repoItem, commitMessage, {main.async{self.onCommitDialogComplete()}}) + GitSync.initCommit(repoItem, commitMessage, { main.async { self.onCommitDialogComplete() } }) } Proxy.styleTestView?.currentPrompt?.removeFromSuperview()/*removes promptView from window*/ - + } } diff --git a/Sources/GitSyncMac/window/view/dialog/commit/CommitDialogView.swift b/Sources/GitSyncMac/window/view/dialog/commit/CommitDialogView.swift index e6a46e26c..fe1d78f8c 100644 --- a/Sources/GitSyncMac/window/view/dialog/commit/CommitDialogView.swift +++ b/Sources/GitSyncMac/window/view/dialog/commit/CommitDialogView.swift @@ -4,17 +4,17 @@ import Cocoa /** * TODO: ⚠️️ Rename to CommitPromptView? */ -class CommitDialogView:Element,UnFoldable,Closable { - var repoItem:RepoItem? - var onCommitDialogComplete:Completed = {print("hmm");fatalError("no completion handler assigned")}/*Stores the onComplete when the user clicks OK*/ - +class CommitDialogView: Element, UnFoldable, Closable { + var repoItem: RepoItem? + var onCommitDialogComplete:Completed = { print("hmm"); fatalError("no completion handler assigned") }/*Stores the onComplete when the user clicks OK*/ + override func resolveSkin() { // Swift.print("🍊 CommitDialogView.resolveSkin()") super.resolveSkin() - Unfold.unFold(fileURL: Config.Bundle.structure,path: "commitDialogView",parent: self) + Unfold.unFold(fileURL: Config.Bundle.structure,path: "commitDialogView", parent: self) NSApp.requestUserAttention(.informationalRequest)//bounce the dock icon } - override func onEvent(_ event:Event) { + override func onEvent(_ event: Event) { if event.assert(.upInside, id: "ok"){ onOKButtonClick() }else if event.assert(.upInside, id: "cancel"){/*stop the auto sync process,remove commit dialog from view*/ @@ -23,4 +23,3 @@ class CommitDialogView:Element,UnFoldable,Closable { } } } - diff --git a/Sources/GitSyncMac/window/view/menu/MenuContainer.swift b/Sources/GitSyncMac/window/view/menu/MenuContainer.swift index 2afdfab45..3964280bc 100644 --- a/Sources/GitSyncMac/window/view/menu/MenuContainer.swift +++ b/Sources/GitSyncMac/window/view/menu/MenuContainer.swift @@ -2,10 +2,10 @@ import Cocoa @testable import Utils @testable import Element -class MenuContainer:Element { - static let buttonTitles:[Nav.ViewType.Main] = [.commit,.repo,.prefs,.stats] +class MenuContainer: Element { + static let buttonTitles: [Nav.ViewType.Main] = [.commit, .repo, .prefs, .stats] var selectGroup:SelectGroup? - + override func resolveSkin() { super.resolveSkin()//skin = SkinResolver.skin(self) createButtons() @@ -14,9 +14,9 @@ class MenuContainer:Element { var buttons:[Selectable] = MenuContainer.buttonTitles.map{ buttonTitle in return self.addSubView(SelectButton.init(isSelected: false, size: CGSize(20,20), id: buttonTitle.rawValue)) } - selectGroup = SelectGroup(buttons,buttons[0]) - func onSelect(event:Event){ - if event.type == SelectEvent.select, let btn:SelectButton = event.origin as? SelectButton{ + selectGroup = SelectGroup(buttons, buttons[0]) + func onSelect(event: Event){ + if event.type == SelectEvent.select, let btn: SelectButton = event.origin as? SelectButton { _ = btn.id // Swift.print("btn.id: " + "\(String(describing: btn.id))") } @@ -29,10 +29,10 @@ extension MenuContainer{ /** * When you click the buttons */ - func onSelectGroupChange(event:Event){ + func onSelectGroupChange(event: Event){ if event === (SelectGroupEvent.change,selectGroup!) { // SelectModifier.unSelectAllExcept(selectGroup!.selected!, selectGroup!.selectables) - let buttonId:String = (selectGroup!.selected as! Element).id! + let buttonId: String = (selectGroup!.selected as! Element).id! Swift.print("LeftBarMenu.onSelect() buttonId: " + "\(buttonId)") let type = Nav.ViewType.Main(rawValue:buttonId)!//<--nice! Nav.setView(.main(type))//👌 @@ -42,10 +42,10 @@ extension MenuContainer{ /** * Selects the button based on Main view enum case 👌 */ - func selectButton(_ view:Nav.ViewType){ + func selectButton(_ view: Nav.ViewType){ switch view { case .main(let viewType): - selectGroup!.selectables.forEach{ + selectGroup!.selectables.forEach { if ($0 as? Element)?.id == viewType.rawValue { $0.setSelected(true) } diff --git a/Sources/GitSyncMac/window/view/menu/components/MenuView.swift b/Sources/GitSyncMac/window/view/menu/components/MenuView.swift index 028295283..9b825d12f 100644 --- a/Sources/GitSyncMac/window/view/menu/components/MenuView.swift +++ b/Sources/GitSyncMac/window/view/menu/components/MenuView.swift @@ -2,12 +2,12 @@ import Foundation @testable import Utils @testable import Element -class LeftSideBar:Element{ - var menuContainer:MenuContainer? - var isLeftBarHidden:Bool = false +class LeftSideBar: Element{ + var menuContainer: MenuContainer? + var isLeftBarHidden: Bool = false override func resolveSkin() { super.resolveSkin() - self.menuContainer = self.addSubView(MenuContainer.init(id:"buttonSection")) - _ = self.addSubView(Element.init(id:"ruler")) + self.menuContainer = self.addSubView(MenuContainer.init(id: "buttonSection")) + _ = self.addSubView(Element.init(id: "ruler")) } } diff --git a/Sources/GitSyncMac/window/view/prefs/PrefsView.swift b/Sources/GitSyncMac/window/view/prefs/PrefsView.swift index 19c231f81..84aac58ff 100644 --- a/Sources/GitSyncMac/window/view/prefs/PrefsView.swift +++ b/Sources/GitSyncMac/window/view/prefs/PrefsView.swift @@ -2,12 +2,12 @@ import Cocoa @testable import Utils @testable import Element /** - * NOTE: this must be a view, if you want to be consistent between macOS and iOS - * TODO: ⚠️️ Save the prefs in json, research how writing to json works - * TODO: ⚠️️ make a reusable setUI,getUI method for the UnFold system - * TODO: ⚠️️ make a reusable event handler that stores the state of the UI + * - NOTE: this must be a view, if you want to be consistent between macOS and iOS + * - TODO: ⚠️️ Save the prefs in json, research how writing to json works + * - TODO: ⚠️️ make a reusable setUI,getUI method for the UnFold system + * - TODO: ⚠️️ make a reusable event handler that stores the state of the UI */ -class PrefsView:Element,UnFoldable,PrefsViewClosable { +class PrefsView: Element, UnFoldable, PrefsViewClosable { override func resolveSkin() { super.resolveSkin()//self.skin = SkinResolver.skin(self) Unfold.unFold(fileURL: Config.Bundle.structure, path: "prefsView", parent: self) @@ -16,18 +16,18 @@ class PrefsView:Element,UnFoldable,PrefsViewClosable { /** * UI events from subComponents goes here */ - override func onEvent(_ event:Event) { + override func onEvent(_ event: Event) { // Swift.print("PrefsView.onEvent event.type: \(event.type)") switch true{ - case event.assert(Event.update,parentID:Key.login): + case event.assert(Event.update, parentID: Key.login): PrefsView.prefs.login = (event as! TextFieldEvent).stringValue - case event.assert(Event.update,parentID:Key.pass): + case event.assert(Event.update,parentID: Key.pass): _ = KeyChainModifier.save("GitSyncApp", (event as! TextFieldEvent).stringValue.dataValue) - case event.assert(Event.update,parentID:Key.local): + case event.assert(Event.update, parentID: Key.local): PrefsView.prefs.local = (event as! TextFieldEvent).stringValue - case event.assert(CheckEvent.check,parentID:Key.darkMode): + case event.assert(CheckEvent.check, parentID: Key.darkMode): self.onDarkThemeCheck() - case event.assert(CheckEvent.check,parentID:Key.notification): + case event.assert(CheckEvent.check, parentID: Key.notification): PrefsView.prefs.notification = (event as! CheckEvent).isChecked/*store the value*/ default: super.onEvent(event)/*forward other events*/ diff --git a/Sources/GitSyncMac/window/view/prefs/utils/PrefsView+Extensions.swift b/Sources/GitSyncMac/window/view/prefs/utils/PrefsView+Extensions.swift index a57372687..63647e294 100644 --- a/Sources/GitSyncMac/window/view/prefs/utils/PrefsView+Extensions.swift +++ b/Sources/GitSyncMac/window/view/prefs/utils/PrefsView+Extensions.swift @@ -8,14 +8,14 @@ extension PrefsView{ /** * When darkmode check button is clicked */ - func onDarkThemeCheck(){ - guard let darkMode:CheckBoxButton = try? UnfoldParser.unfoldable(parent:self, path:["darkModeGroup",Key.darkMode]) else {fatalError("darkModeBtn not available")} + func onDarkThemeCheck() { + guard let darkMode: CheckBoxButton = try? UnfoldParser.unfoldable(parent: self, path: ["darkModeGroup", Key.darkMode]) else { fatalError("darkModeBtn not available") } PrefsView.prefs.darkMode = darkMode.getChecked() StyleManager.reset()//clear the old styles - let themeStr:String = darkMode.getChecked() ? "dark.css" : "light.css" - let styleFilePath:String = Config.Bundle.styles + "styles/styletest/" + themeStr - StyleManager.addStyle(url:styleFilePath,liveEdit:false) - if let win:NSWindow = WinParser.focusedWindow(), let styleTestWin:NSWindow = win as? StyleTestWin, let styleTestView = styleTestWin.contentView as? StyleTestView{ + let themeStr: String = darkMode.getChecked() ? "dark.css" : "light.css" + let styleFilePath: String = Config.Bundle.styles + "styles/styletest/" + themeStr + StyleManager.addStyle(url: styleFilePath, liveEdit: false) + if let win: NSWindow = WinParser.focusedWindow(), let styleTestWin: NSWindow = win as? StyleTestWin, let styleTestView = styleTestWin.contentView as? StyleTestView { Swift.print("refreshSkin init") ElementModifier.refreshSkin(styleTestView)//TODO: ⚠️️ time this, does it take long? Swift.print("refreshSkin completed") @@ -32,19 +32,19 @@ extension PrefsView{ /** * Parsing */ -extension PrefsView{ - static var prefs:PrefsData = { +extension PrefsView { + static var prefs: PrefsData = { return PrefsData.prefsData//basically this is read 1 time and then reused aka not regenerated everytime its called }() /** * Applies prefsData to the PrefsView */ - func setPrefs(_ prefs:PrefsData){ - self.apply([Key.login,TextInput.Key.inputText],prefs.login) + func setPrefs(_ prefs: PrefsData){ + self.apply([Key.login, TextInput.Key.inputText], prefs.login) let passStr = KeyChainParser.password("GitSyncApp") ?? "" - self.apply([Key.pass,TextInput.Key.inputText],passStr) - self.apply([Key.local,TextInput.Key.inputText],prefs.local) - self.apply(["darkModeGroup",Key.darkMode],prefs.darkMode) - self.apply([Section.Key.group,Key.notification],prefs.notification) + self.apply([Key.pass, TextInput.Key.inputText], passStr) + self.apply([Key.local, TextInput.Key.inputText], prefs.local) + self.apply(["darkModeGroup", Key.darkMode], prefs.darkMode) + self.apply([Section.Key.group, Key.notification], prefs.notification) } } diff --git a/Sources/GitSyncMac/window/view/prefs/utils/data/PrefsData+Extensions.swift b/Sources/GitSyncMac/window/view/prefs/utils/data/PrefsData+Extensions.swift index a775f9787..f9dc3d888 100644 --- a/Sources/GitSyncMac/window/view/prefs/utils/data/PrefsData+Extensions.swift +++ b/Sources/GitSyncMac/window/view/prefs/utils/data/PrefsData+Extensions.swift @@ -7,7 +7,7 @@ extension PrefsData{ /** * Grabs data from prefs, which is garantued to hold data regardless if PrefsView was ever created */ - static var xml:XML{ + static var xml: XML{ let xml:XML = "".xml let prefs = PrefsView.prefs xml.appendChild("<\(Key.login)>\(prefs.login)".xml) @@ -23,10 +23,10 @@ extension PrefsData{ return xml } /** - * NOTE: this is re-generated on every call - * TODO: ⚠️️ Use the unfold utils instead maybe? + * - NOTE: this is re-generated on every call + * - TODO: ⚠️️ Use the unfold utils instead maybe? */ - static var prefsData:PrefsData{ + static var prefsData: PrefsData { let xml:XML = FileParser.xml(Config.Bundle.prefsURL.tildePath)/*Loads the xml*/ let login = xml.firstNode(Key.login)!.stringValue! let local = xml.firstNode(Key.local)!.stringValue! @@ -34,31 +34,29 @@ extension PrefsData{ let notification = xml.firstNode(Key.notification)!.stringValue!.bool let w = xml.firstNode(Key.w)!.stringValue!.cgFloat let h = xml.firstNode(Key.h)!.stringValue!.cgFloat - let x:CGFloat = {//TODO: ⚠️️ refactor this when you have time + let x: CGFloat = {//TODO: ⚠️️ refactor this when you have time if let xSTR:String = xml.firstNode(Key.x)?.stringValue,!xSTR.isEmpty { return xSTR.cgFloat } else { return NaN } }() - let y:CGFloat = {//TODO: ⚠️️ refactor this when you have time - if let ySTR:String = xml.firstNode(Key.y)?.stringValue,!ySTR.isEmpty { + let y: CGFloat = {//TODO: ⚠️️ refactor this when you have time + if let ySTR:String = xml.firstNode(Key.y)?.stringValue, !ySTR.isEmpty { return ySTR.cgFloat } else { return NaN } }() - let rect:CGRect = CGRect(x,y,w,h) - return .init(login:login,pass:"",local:local,darkMode:darkMode,notification:notification,rect:rect) + let rect: CGRect = CGRect(x, y, w, h) + return .init(login: login, pass: "", local: local, darkMode: darkMode, notification: notification, rect: rect) } } -protocol PrefsViewClosable:Closable{} -extension PrefsViewClosable{ +protocol PrefsViewClosable: Closable { } +extension PrefsViewClosable { func close() { _ = FileModifier.write(Config.Bundle.prefsURL.tildePath, PrefsData.xml.xmlString)/*Stores the app prefs*/ Swift.print("💾 Write PrefsView to: prefs.xml") self.removeFromSuperview() } } - - diff --git a/Sources/GitSyncMac/window/view/prefs/utils/data/PrefsData.swift b/Sources/GitSyncMac/window/view/prefs/utils/data/PrefsData.swift index 0118b31a6..232d31ecf 100644 --- a/Sources/GitSyncMac/window/view/prefs/utils/data/PrefsData.swift +++ b/Sources/GitSyncMac/window/view/prefs/utils/data/PrefsData.swift @@ -1,11 +1,10 @@ import Foundation struct PrefsData { - var login:String - var pass:String - var local:String - var darkMode:Bool - var notification:Bool - var rect:CGRect + var login: String + var pass: String + var local: String + var darkMode: Bool + var notification: Bool + var rect: CGRect } - diff --git a/Sources/GitSyncMac/window/view/repo/RepoContextMenu.swift b/Sources/GitSyncMac/window/view/repo/RepoContextMenu.swift index e6d4b5663..17a514cf3 100644 --- a/Sources/GitSyncMac/window/view/repo/RepoContextMenu.swift +++ b/Sources/GitSyncMac/window/view/repo/RepoContextMenu.swift @@ -6,14 +6,14 @@ import Cocoa * Right click context menu * TODO: ⚠️️ maybe create sub menus to appear more organized? */ -class RepoContextMenu:NSMenu{ - var rightClickItemIdx:[Int]? - var clipBoard:XML? - var treeList:TreeListable3 - init(_ treeList:TreeListable3) { +class RepoContextMenu: NSMenu { + var rightClickItemIdx: [Int]? + var clipBoard: XML? + var treeList: TreeListable3 + init(_ treeList: TreeListable3) { self.treeList = treeList//Element - mac super.init(title:"Contextual menu") - let menuItems:[(title:RepoMenuItem,selector:Foundation.Selector)] = [ + let menuItems:[(title: RepoMenuItem, selector: Foundation.Selector)] = [ (.newGroup, #selector(newGroup)) , (.newRepo, #selector(newRepo)) , (.duplicate, #selector(duplicate)) @@ -29,25 +29,25 @@ class RepoContextMenu:NSMenu{ , (.openUrl, #selector(openURL)) ] //continue here: add Open in github - menuItems.forEach{ - let menuItem = NSMenuItem(title: $0.title.rawValue, action: $0.selector, keyEquivalent: "") + menuItems.forEach { + let menuItem: NSMenuItem = .init(title: $0.title.rawValue, action: $0.selector, keyEquivalent: "") self.addItem(menuItem) menuItem.target = self } self.insertItem(NSMenuItem.separator(), at: 7)/*Separator*/ self.insertItem(NSMenuItem.separator(), at: 12)/*Separator*/ } - required init(coder decoder: NSCoder) {fatalError("init(coder:) has not been implemented")} + required init(coder decoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } /** * Right click Context menu methods */ extension RepoContextMenu{ /** - * TODO: ⚠️️ A bug is that when you add a folder and its the last item then the list isnt resized - * TODO: ⚠️️ There is a bug if you add items to closed groups, then there will be an error + * - TODO: ⚠️️ A bug is that when you add a folder and its the last item then the list isnt resized + * - TODO: ⚠️️ There is a bug if you add items to closed groups, then there will be an error */ - @objc func newGroup(sender:AnyObject) { + @objc func newGroup(sender: AnyObject) { Swift.print("newFolder") let idx = rightClickItemIdx! let xmlStr:String = ""//hasChildren=\"true\" @@ -56,12 +56,12 @@ extension RepoContextMenu{ treeList.insert(newIdx,tree) Swift.print("Promt folder name popup") } - @objc func newRepo(sender:AnyObject) { + @objc func newRepo(sender: AnyObject) { Swift.print("newRepo") //treeList.insert([1],Tree("item",[],nil,["title":"Fish"]))/*Insert item at let idx = rightClickItemIdx! Swift.print("idx: " + "\(idx)") - let props:[String:String] = [ + let props: [String: String] = [ RepoItem.Key.title:"New repo", RepoItem.Key.local:"~/Desktop/test", RepoItem.Key.remote:"https://github.com/eonist/test.git", @@ -69,52 +69,52 @@ extension RepoContextMenu{ RepoItem.Key.message:"true", RepoItem.Key.active:"true", RepoItem.Key.auto:"true"] - let tree:Tree = Tree.init("item", [], nil, props) + let tree:Tree = .init("item", [], nil, props) let newIdx = Utils.newIdx(treeList,idx) treeList.insert(newIdx,tree) //Swift.print("Promt repo name popup") } - @objc func duplicate(sender:AnyObject) { + @objc func duplicate(sender: AnyObject) { Swift.print("duplicate") let idx = rightClickItemIdx! Swift.print("idx: " + "\(idx)") - if let tree:Tree = treeList[idx] { + if let tree: Tree = treeList[idx] { let newIdx = Utils.newIdx(treeList,idx) treeList.insert(newIdx, tree) } } - @objc func doCopy(sender:AnyObject) { + @objc func doCopy(sender: AnyObject) { Swift.print("copy") let idx = rightClickItemIdx! Swift.print("idx: " + "\(idx)") - if let tree:Tree = treeList[idx] { + if let tree: Tree = treeList[idx] { clipBoard = tree.xml Swift.print("clipBoard: " + "\(clipBoard!.string)") } } - @objc func cut(sender:AnyObject) { + @objc func cut(sender: AnyObject) { Swift.print("cut") let idx = rightClickItemIdx! Swift.print("idx: " + "\(idx)") - if let tree:Tree = treeList[idx] { + if let tree: Tree = treeList[idx] { treeList.remove(idx) clipBoard = tree.xml Swift.print("clipBoard: " + "\(clipBoard!.string)") } } - @objc func paste(sender:AnyObject) { + @objc func paste(sender: AnyObject) { Swift.print("paste") if let idx3d = rightClickItemIdx, let clipBoard:XML = clipBoard{ Swift.print("idx: " + "\(idx3d)") //Swift.print("clipBoard: " + "\(self.clipBoard)") - - + + let newIdx = Utils.newIdx(treeList,idx3d) let tree = TreeConverter.tree(clipBoard) treeList.insert(newIdx, tree) } } - @objc func delete(sender:AnyObject) { + @objc func delete(sender: AnyObject) { Swift.print("delete") if let idx = rightClickItemIdx { treeList.remove(idx) @@ -124,33 +124,33 @@ extension RepoContextMenu{ } } /*move up down top bottom.*/ - @objc func moveUp(sender:AnyObject){ + @objc func moveUp(sender: AnyObject){ Swift.print("moveUp") if let idx3d = rightClickItemIdx { TreeList3Modifier.moveUp(treeList, idx3d) } } - @objc func moveDown(sender:AnyObject){ + @objc func moveDown(sender: AnyObject){ Swift.print("moveDown") if let idx3d = rightClickItemIdx { TreeList3Modifier.moveDown(treeList, idx3d) } } - @objc func moveToTop(sender:AnyObject){ + @objc func moveToTop(sender: AnyObject){ Swift.print("moveToTop") if let idx3d = rightClickItemIdx { TreeList3Modifier.moveTop(treeList, idx3d) } } - @objc func moveToBottom(sender:AnyObject){ + @objc func moveToBottom(sender: AnyObject){ Swift.print("moveToBottom") if let idx3d = rightClickItemIdx { TreeList3Modifier.moveBottom(treeList, idx3d) } } - @objc func showInFinder(sender:AnyObject){ + @objc func showInFinder(sender: AnyObject){ Swift.print("showInFinder") - if let idx = rightClickItemIdx, !TreeList3Asserter.hasChildren(treeList,idx) { + if let idx = rightClickItemIdx, !TreeList3Asserter.hasChildren(treeList, idx) { /*Only repos can be opened in finder*/ let repoItem = RepoUtils.repoItem(xml: treeList.xml, idx: idx) if FileAsserter.exists(repoItem.local.tildePath) {/*make sure local-path exists*/ @@ -158,10 +158,10 @@ extension RepoContextMenu{ } } } - @objc func openURL(sender:AnyObject){ + @objc func openURL(sender: AnyObject){ Swift.print("openURL") if let idx = rightClickItemIdx { - let hasChildren:Bool = treeList.hasChildren(idx) + let hasChildren: Bool = treeList.hasChildren(idx) if !hasChildren {/*Only repos can be opened in finder*/ let repoItem = RepoUtils.repoItem(xml: treeList.xml, idx: idx) NetworkUtils.openURLInDefaultBrowser(repoItem.remote) @@ -169,7 +169,7 @@ extension RepoContextMenu{ } } } -enum RepoMenuItem:String { +enum RepoMenuItem: String { case newGroup = "New group" case newRepo = "New repo" case duplicate = "Duplicate" @@ -189,7 +189,7 @@ private class Utils { * Returns a new idx * NOTE: isFolder -> add within, is not folder -> add bellow */ - static func newIdx(_ treeList:TreeListable3,_ idx3d:[Int]) -> [Int] { + static func newIdx(_ treeList: TreeListable3, _ idx3d: [Int]) -> [Int] { var idx3d = idx3d //let itemData:ItemData3 = TreeList3Utils.itemData(treeList, idx) let isGroup:Bool = TreeAsserter.hasAttribute(treeList.tree, idx3d, RepoFolderType.isOpen.rawValue) diff --git a/Sources/GitSyncMac/window/view/repo/RepoView+Extensions.swift b/Sources/GitSyncMac/window/view/repo/RepoView+Extensions.swift index 6adbd1222..e7dc08327 100644 --- a/Sources/GitSyncMac/window/view/repo/RepoView+Extensions.swift +++ b/Sources/GitSyncMac/window/view/repo/RepoView+Extensions.swift @@ -3,8 +3,8 @@ import Foundation @testable import Element extension RepoView{ - func onTreeListSelect(){ - let selectedIndex:[Int] = treeList.selectedIdx3d! + func onTreeListSelect() { + let selectedIndex: [Int] = treeList.selectedIdx3d! //Swift.print("selectedIndex: " + "\(selectedIndex)") Nav.setView(.detail(.repo(selectedIndex)))/*Updates the UI elements with the selected repo data*/ } @@ -16,9 +16,8 @@ extension RepoView{ // Swift.print("size: " + "\(size)") let thumbSize = CGSize(self.getWidth(),24) // Swift.print("thumbSize: " + "\(thumbSize)") - let treeList:TreeList5 = .init(config:.init(itemSize: thumbSize, dp: RepoView.treeDP, dir: .ver), size: size) + let treeList: TreeList5 = .init(config: .init(itemSize: thumbSize, dp: RepoView.treeDP, dir: .ver), size: size) return self.addSubView(treeList)//TreeList3(size.w,size.h,thumbSize , RepoView.treeDP, self) //if(RepoView.selectedListItemIndex.count > 0){TreeListModifier.selectAt(treeList!, RepoView.selectedListItemIndex)} } } - diff --git a/Sources/GitSyncMac/window/view/repo/RepoView.swift b/Sources/GitSyncMac/window/view/repo/RepoView.swift index a3a0810eb..7759b5c9d 100644 --- a/Sources/GitSyncMac/window/view/repo/RepoView.swift +++ b/Sources/GitSyncMac/window/view/repo/RepoView.swift @@ -2,27 +2,27 @@ import Cocoa @testable import Utils @testable import Element /** - * TODO: ⚠️️ Should remember previous selected item between transitions - * TODO: use singleton instead of the bellow ⚠️️ + * - TODO: ⚠️️ Should remember previous selected item between transitions + * - TODO: use singleton instead of the bellow ⚠️️ */ -class RepoView:Element,Closable { - static var selectedListItemIndex:[Int] = [] - static var _treeDP:TreeDP? = nil - static var treeDP:TreeDP {//TODO: ⚠️️ all this may not be needed, test if you need to invalidate etc. +class RepoView: Element, Closable { + static var selectedListItemIndex: [Int] = [] + static var _treeDP: TreeDP? = nil + static var treeDP: TreeDP {//TODO: ⚠️️ all this may not be needed, test if you need to invalidate etc. guard let treeDP = _treeDP else{ _treeDP = TreeDP(Config.Bundle.repo.tildePath)/*Doesn't exists return new DP*/ return _treeDP! };return treeDP/*Already exist, return old dp*/ } - lazy var treeList:TreeList5 = createTreeList() - lazy var contextMenu:RepoContextMenu = {return RepoContextMenu(self.treeList)}() + lazy var treeList: TreeList5 = createTreeList() + lazy var contextMenu: RepoContextMenu = { return RepoContextMenu(self.treeList) }() override func resolveSkin() { super.resolveSkin()//self.skin = SkinResolver.skin(self)// _ = treeList _ = contextMenu } - override func onEvent(_ event:Event) { - if event.assert(ListEvent.select,treeList) {//if(event.type == SelectEvent.select && event.immediate === treeList){} + override func onEvent(_ event: Event) { + if event.assert(ListEvent.select, treeList) {//if(event.type == SelectEvent.select && event.immediate === treeList){} //Swift.print("RepoView.onTreeListEvent() selectedIndex: " + "\(treeList.selectedIdx3d)") onTreeListSelect() }else if event.type == ButtonEvent.rightMouseDown { @@ -34,4 +34,3 @@ class RepoView:Element,Closable { } } } - diff --git a/Sources/GitSyncMac/window/view/repo/detail/RepoDetailView.swift b/Sources/GitSyncMac/window/view/repo/detail/RepoDetailView.swift index 4cb44ad21..597630282 100644 --- a/Sources/GitSyncMac/window/view/repo/detail/RepoDetailView.swift +++ b/Sources/GitSyncMac/window/view/repo/detail/RepoDetailView.swift @@ -2,45 +2,43 @@ import Foundation @testable import Utils @testable import Element -class RepoDetailView:Element,Closable,UnFoldable { +class RepoDetailView: Element, Closable, UnFoldable { /** * Init the UI */ override func resolveSkin() { super.resolveSkin() let idx3d = RepoView.selectedListItemIndex - let isFolder = TreeDPAsserter.hasChildren(RepoView.treeDP, idx3d) - if isFolder { let folderJson = self.folderJson(fileURL: Config.Bundle.structure, path: "repoDetailView") Unfold.unFold(jsonArr:folderJson, parent: self) }else{ - Unfold.unFold(fileURL:Config.Bundle.structure, path:"repoDetailView", parent:self) + Unfold.unFold(fileURL: Config.Bundle.structure, path: "repoDetailView", parent: self) } } - + /** * Modifies the dataProvider item on UI change */ - override func onEvent(_ event:Event) { + override func onEvent(_ event: Event) { Swift.print("RepoDetailView.onEvent: type: " + "\(event.type) immediate: \(event.immediate) origin: \(event.origin)") - let idx3d:[Int] = RepoView.selectedListItemIndex - var repoItem:RepoItem = RepoItem.repoItem(treeDP: RepoView.treeDP, idx3d: idx3d) - + let idx3d: [Int] = RepoView.selectedListItemIndex + var repoItem: RepoItem = RepoItem.repoItem(treeDP: RepoView.treeDP, idx3d: idx3d) + switch true{ - case event.assert(TextFieldEvent.update,parentID:Key.title):/*title*/ + case event.assert(TextFieldEvent.update, parentID: Key.title):/*title*/ repoItem.title = (event as! TextFieldEvent).stringValue - case event.assert(TextFieldEvent.update,parentID:Key.local):/*local*/ + case event.assert(TextFieldEvent.update, parentID:Key.local):/*local*/ repoItem.local = (event as! TextFieldEvent).stringValue - case event.assert(TextFieldEvent.update,parentID:Key.remote):/*remote*/ + case event.assert(TextFieldEvent.update, parentID:Key.remote):/*remote*/ repoItem.remote = (event as! TextFieldEvent).stringValue - case event.assert(TextFieldEvent.update,parentID:Key.branch):/*branch*/ + case event.assert(TextFieldEvent.update, parentID:Key.branch):/*branch*/ repoItem.branch = (event as! TextFieldEvent).stringValue - case event.assert(TextFieldEvent.update,parentID:Key.template):/*template*/ + case event.assert(TextFieldEvent.update, parentID:Key.template):/*template*/ repoItem.template = (event as! TextFieldEvent).stringValue case event.assert(.check): - repoItem = onCheckEvent(event as! CheckEvent,&repoItem) + repoItem = onCheckEvent(event as! CheckEvent, &repoItem) default: super.onEvent(event)/*forward other events*/ break; @@ -56,7 +54,7 @@ class RepoDetailView:Element,Closable,UnFoldable { /** * New */ - func onCheckEvent(_ event:CheckEvent,_ repoItem: inout RepoItem) -> RepoItem{ + func onCheckEvent(_ event:CheckEvent,_ repoItem: inout RepoItem) -> RepoItem { // let idx3d = RepoView.selectedListItemIndex // let isFolder = TreeDPAsserter.hasChildren(RepoView.treeDP, idx3d) // @@ -66,19 +64,19 @@ class RepoDetailView:Element,Closable,UnFoldable { // TreeModifier.applyAll(tree: &RepoView.treeDP.tree, idx3d: idx3d, apply: {/*Swift.print($0.props?["title"]);*/$0.props?[key] = value.str}) // } // } - + switch true{ case event.assert(parentID: Key.active):/*active*/ repoItem[Key.active] = value // closure(Key.active,event.checked) // Swift.print("repoItem.active: " + "\(repoItem.active)") - case event.assert(parentID:Key.message):/*message*/ + case event.assert(parentID: Key.message):/*message*/ repoItem[Key.message] = value // closure(Key.message,event.checked) - case event.assert(parentID:Key.auto):/*auto*/ + case event.assert(parentID: Key.auto):/*auto*/ repoItem[Key.auto] = value // closure(Key.auto,event.checked) - case event.assert(parentID:Key.notification):/*notification*/ + case event.assert(parentID: Key.notification):/*notification*/ repoItem[Key.notification] = value // closure(Key.notification,event.checked) default: diff --git a/Sources/GitSyncMac/window/view/repo/detail/utils/RepoDetailView+Key.swift b/Sources/GitSyncMac/window/view/repo/detail/utils/RepoDetailView+Key.swift index 4ad4b0bad..610dd49cc 100644 --- a/Sources/GitSyncMac/window/view/repo/detail/utils/RepoDetailView+Key.swift +++ b/Sources/GitSyncMac/window/view/repo/detail/utils/RepoDetailView+Key.swift @@ -1,7 +1,7 @@ import Foundation @testable import Utils -extension RepoDetailView{ +extension RepoDetailView { typealias Key = RepoItem.Key - + } diff --git a/Sources/GitSyncMac/window/view/repo/detail/utils/RepodetailView+Extensions.swift b/Sources/GitSyncMac/window/view/repo/detail/utils/RepodetailView+Extensions.swift index d89bbcb18..b2d406cff 100644 --- a/Sources/GitSyncMac/window/view/repo/detail/utils/RepodetailView+Extensions.swift +++ b/Sources/GitSyncMac/window/view/repo/detail/utils/RepodetailView+Extensions.swift @@ -5,46 +5,46 @@ import Foundation extension RepoDetailView{ /** * Populates the UI elements with data from the dp item - * NOTE: Uses the Unfold lib to set data + * - NOTE: Uses the Unfold lib to set data */ - public func setRepoData(){ + public func setRepoData() { let idx3d = RepoView.selectedListItemIndex let repoItem = RepoItem.repoItem(treeDP: RepoView.treeDP, idx3d: idx3d) - + Swift.print("setRepoData(repoItem)") /*TextInput*/ - self.apply([Key.title],repoItem.title) - self.apply([Key.local],repoItem.local) - self.apply([Key.remote],repoItem.remote) - self.apply([Key.branch],repoItem.branch) - self.apply([Key.template],repoItem.template) - + self.apply([Key.title], repoItem.title) + self.apply([Key.local], repoItem.local) + self.apply([Key.remote], repoItem.remote) + self.apply([Key.branch], repoItem.branch) + self.apply([Key.template], repoItem.template) + /*CheckButtons*/ - let closure = { (path:[String],key:String) in - if let ui:CheckBoxButton = try? UnfoldParser.unfoldable(parent:self, path:path) { + let closure = { (path: [String], key: String) in + if let ui: CheckBoxButton = try? UnfoldParser.unfoldable(parent: self, path: path) { // Swift.print("ui: " + "\(ui)") - guard let checkedState:Bool = repoItem[key] else {fatalError("err")}//Utils.checkedState(repoItem,idx3d,key) + guard let checkedState: Bool = repoItem[key] else { fatalError("err") }//Utils.checkedState(repoItem,idx3d,key) // Swift.print("checkedState: " + "\(checkedState)") ui.value = checkedState//.rawValue //we use string not enum state } } - closure(["autoGroup",Key.auto],Key.auto) - closure(["messageGroup",Key.message],Key.message) - closure(["activeGroup",Key.active],Key.active) - closure(["notificationGroup",Key.notification],Key.notification) + closure(["autoGroup", Key.auto], Key.auto) + closure(["messageGroup", Key.message], Key.message) + closure(["activeGroup", Key.active], Key.active) + closure(["notificationGroup", Key.notification], Key.notification) } /** * New, this is used when unfolding RepoDetailViews that are folder types */ - func folderJson(fileURL:String,path:String) -> [[String:Any]]{ - guard let jsonDict:[String: Any] = JSONParser.dict(fileURL.content?.json) else{fatalError("fileURL: is incorrect: \(fileURL)")} - guard let jsonDictItem:Any = jsonDict[path] else{fatalError("path is incorrect: \(path)")} - guard let jsonArr:[[String:Any]] = JSONParser.dictArr(jsonDictItem) else{fatalError("jsonDictItem: is incorrect")} + func folderJson(fileURL: String, path: String) -> [[String: Any]] { + guard let jsonDict: [String: Any] = JSONParser.dict(fileURL.content?.json) else { fatalError("fileURL: is incorrect: \(fileURL)") } + guard let jsonDictItem: Any = jsonDict[path] else { fatalError("path is incorrect: \(path)") } + guard let jsonArr: [[String:Any]] = JSONParser.dictArr(jsonDictItem) else{fatalError("jsonDictItem: is incorrect") } let matchs = ["title","activeGroup","autoGroup","notificationGroup","messageGroup"] - let filteredJsonArr = jsonArr.filter{ - guard let id:String = $0["id"] as? String else {fatalError("err")} + let filteredJsonArr = jsonArr.filter { + guard let id: String = $0["id"] as? String else { fatalError("err") } // Swift.print("id: " + "\(id)") - let match:Bool = ArrayAsserter.has(matchs, id) + let match: Bool = ArrayAsserter.has(matchs, id) // Swift.print("match: " + "\(match)") return match } @@ -52,8 +52,8 @@ extension RepoDetailView{ } } -protocol RepoDetailViewClosable:Closable{} -extension RepoDetailView{ +protocol RepoDetailViewClosable: Closable { } +extension RepoDetailView { func close() { // Swift.print("Close") _ = FileModifier.write(Config.Bundle.repo.tildePath, RepoView.treeDP.tree.xml.xmlString)/*store the repo xml*/ @@ -88,8 +88,7 @@ extension RepoDetailView{ //// Swift.print("prop: " + "\(prop)") // return prop ? .checked : .none // } -// -// +// +// // } //} - diff --git a/Sources/GitSyncMac/window/view/repo/detail/utils/data/RepoItem+TreeDP+Extensions.swift b/Sources/GitSyncMac/window/view/repo/detail/utils/data/RepoItem+TreeDP+Extensions.swift index a1f565a38..40fba1769 100644 --- a/Sources/GitSyncMac/window/view/repo/detail/utils/data/RepoItem+TreeDP+Extensions.swift +++ b/Sources/GitSyncMac/window/view/repo/detail/utils/data/RepoItem+TreeDP+Extensions.swift @@ -6,27 +6,26 @@ extension RepoItem{ /** * New */ - var dict:[String:String] {return ReflectUtils.dictionary(instance:self)} + var dict:[String: String] { return ReflectUtils.dictionary(instance: self) } /** * Creates repoDetailData from tree attribs at idx3d - * //TODO: ⚠️️ Use the RepoItem on the bellow line see AutoSync class for implementation + * - TODO: ⚠️️ Use the RepoItem on the bellow line see AutoSync class for implementation */ - static func repoItem(treeDP:TreeDP,idx3d:[Int]) -> RepoItem { - if let tree:Tree = treeDP.tree[idx3d], let repoItemDict = tree.props{//NodeParser.dataAt(treeList!.node, selectedIndex) - var repoItem:RepoItem - let hasIsOpenAttrib:Bool = TreeAsserter.hasAttribute(RepoView.treeDP.tree, idx3d, "isOpen") - + static func repoItem(treeDP: TreeDP, idx3d: [Int]) -> RepoItem { + if let tree: Tree = treeDP.tree[idx3d], let repoItemDict = tree.props {//NodeParser.dataAt(treeList!.node, selectedIndex) + var repoItem: RepoItem + let hasIsOpenAttrib: Bool = TreeAsserter.hasAttribute(RepoView.treeDP.tree, idx3d, "isOpen") + // Swift.print("hasIsOpenAttrib: " + "\(hasIsOpenAttrib)") if !tree.children.isEmpty || hasIsOpenAttrib {/*Support for folders*/ repoItem = RepoItem() - if let title:String = repoItemDict[Key.title] {repoItem.title = title} - if let active:String = repoItemDict[Key.active] {repoItem.active = active.bool} + if let title: String = repoItemDict[Key.title] {repoItem.title = title} + if let active: String = repoItemDict[Key.active] {repoItem.active = active.bool} }else{ repoItem = RepoUtils.repoItem(dict:repoItemDict) } - return repoItem//RepoDetailData.init(repoItem:repoItem) - }else{ + } else { fatalError("Unable to derive repoItem from TreeDP") } }