@@ -15,18 +15,27 @@ import CoreSpotlight
1515/// If a UI element needs to listen to changes in this list, listen for the
1616/// ``RecentProjectsStore/didUpdateNotification`` notification.
1717enum RecentProjectsStore {
18- private static let defaultsKey = " recentProjectPaths "
18+ private static let projectsdDefaultsKey = " recentProjectPaths "
19+ private static let fileDefaultsKey = " recentFilePaths "
1920 static let didUpdateNotification = Notification . Name ( " RecentProjectsStore.didUpdate " )
2021
2122 static func recentProjectPaths( ) -> [ String ] {
22- UserDefaults . standard. array ( forKey: defaultsKey ) as? [ String ] ?? [ ]
23+ UserDefaults . standard. array ( forKey: projectsdDefaultsKey ) as? [ String ] ?? [ ]
2324 }
2425
2526 static func recentProjectURLs( ) -> [ URL ] {
26- recentProjectPaths ( ) . map { URL ( filePath: $0) }
27+ return recentProjectPaths ( ) . map { URL ( filePath: $0) }
2728 }
2829
29- private static func setPaths( _ paths: [ String ] ) {
30+ static func recentFilePaths( ) -> [ String ] {
31+ UserDefaults . standard. array ( forKey: fileDefaultsKey) as? [ String ] ?? [ ]
32+ }
33+
34+ static func recentFileURLs( ) -> [ URL ] {
35+ return recentFilePaths ( ) . map { URL ( filePath: $0) }
36+ }
37+
38+ private static func setProjectPaths( _ paths: [ String ] ) {
3039 var paths = paths
3140 // Remove duplicates
3241 var foundPaths = Set < String > ( )
@@ -39,7 +48,25 @@ enum RecentProjectsStore {
3948 }
4049
4150 // Limit list to to 100 items after de-duplication
42- UserDefaults . standard. setValue ( Array ( paths. prefix ( 100 ) ) , forKey: defaultsKey)
51+ UserDefaults . standard. setValue ( Array ( paths. prefix ( 100 ) ) , forKey: projectsdDefaultsKey)
52+ setDocumentControllerRecents ( )
53+ donateSearchableItems ( )
54+ NotificationCenter . default. post ( name: Self . didUpdateNotification, object: nil )
55+ }
56+ private static func setFilePaths( _ paths: [ String ] ) {
57+ var paths = paths
58+ // Remove duplicates
59+ var foundPaths = Set < String > ( )
60+ for (idx, path) in paths. enumerated ( ) . reversed ( ) {
61+ if foundPaths. contains ( path) {
62+ paths. remove ( at: idx)
63+ } else {
64+ foundPaths. insert ( path)
65+ }
66+ }
67+
68+ // Limit list to to 100 items after de-duplication
69+ UserDefaults . standard. setValue ( Array ( paths. prefix ( 100 ) ) , forKey: fileDefaultsKey )
4370 setDocumentControllerRecents ( )
4471 donateSearchableItems ( )
4572 NotificationCenter . default. post ( name: Self . didUpdateNotification, object: nil )
@@ -50,29 +77,58 @@ enum RecentProjectsStore {
5077 /// Saves the list to defaults when called.
5178 /// - Parameter url: The url that was opened. Any url is accepted. File, directory, https.
5279 static func documentOpened( at url: URL ) {
53- var paths = recentProjectURLs ( )
54- if let containedIndex = paths. firstIndex ( where: { $0. componentCompare ( url) } ) {
55- paths. move ( fromOffsets: IndexSet ( integer: containedIndex) , toOffset: 0 )
80+ var projPaths = recentProjectURLs ( )
81+ var filePaths = recentFileURLs ( )
82+
83+ let urlToString = url. absoluteString
84+
85+ // if file portion of local URL has "/" at the end then it is a folder , files and folders go in two separate lists
86+
87+ if urlToString. hasSuffix ( " / " ) {
88+ if let containedIndex = projPaths. firstIndex ( where: { $0. componentCompare ( url) } ) {
89+ projPaths. move ( fromOffsets: IndexSet ( integer: containedIndex) , toOffset: 0 )
90+ } else {
91+ projPaths. insert ( url, at: 0 )
92+ }
93+ setProjectPaths ( projPaths. map { $0. path ( percentEncoded: false ) } )
5694 } else {
57- paths. insert ( url, at: 0 )
95+ if let containedIndex = filePaths. firstIndex ( where: { $0. componentCompare ( url) } ) {
96+ filePaths. move ( fromOffsets: IndexSet ( integer: containedIndex) , toOffset: 0 )
97+ } else {
98+ filePaths. insert ( url, at: 0 )
99+ }
100+ setFilePaths ( filePaths. map { $0. path ( percentEncoded: false ) } )
58101 }
59- setPaths ( paths. map { $0. path ( percentEncoded: false ) } )
60102 }
61103
62- /// Remove all paths in the set.
104+ /// Remove all project paths in the set.
63105 /// - Parameter paths: The paths to remove.
64106 /// - Returns: The remaining urls in the recent projects list.
65107 static func removeRecentProjects( _ paths: Set < URL > ) -> [ URL ] {
66108 var recentProjectPaths = recentProjectURLs ( )
67109 recentProjectPaths. removeAll ( where: { paths. contains ( $0) } )
68- setPaths ( recentProjectPaths. map { $0. path ( percentEncoded: false ) } )
110+ setProjectPaths ( recentProjectPaths. map { $0. path ( percentEncoded: false ) } )
69111 return recentProjectURLs ( )
70112 }
113+ /// Remove all folder paths in the set.
114+ /// - Parameter paths: The paths to remove.
115+ /// - Returns: The remaining urls in the recent projects list.
116+
117+ static func removeRecentFiles( _ paths: Set < URL > ) -> [ URL ] {
118+ var recentFilePaths = recentFileURLs ( )
119+ recentFilePaths. removeAll ( where: { paths. contains ( $0) } )
120+ setFilePaths ( recentFilePaths. map { $0. path ( percentEncoded: false ) } )
121+ return recentFileURLs ( )
122+ }
71123
72124 static func clearList( ) {
73- setPaths ( [ ] )
125+ setProjectPaths ( [ ] )
126+ setFilePaths ( [ ] )
127+ NotificationCenter . default. post ( name: Self . didUpdateNotification, object: nil )
74128 }
75-
129+ // TODO do we need to setdocument controller for Projects AND Files????
130+ // doesn't seem like it clears in teh finder anyway
131+ // ...more testing whcn Cleairng list required.
76132 /// Syncs AppKit's recent documents list with ours, keeping the dock menu and other lists up-to-date.
77133 private static func setDocumentControllerRecents( ) {
78134 CodeEditDocumentController . shared. clearRecentDocuments ( nil )
0 commit comments