diff --git a/VimR.xcodeproj/project.pbxproj b/VimR.xcodeproj/project.pbxproj index 1ec2b43f..ce285a48 100644 --- a/VimR.xcodeproj/project.pbxproj +++ b/VimR.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 1929B73E5EC0B108B83F82EB /* FileItemService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B3A98687DF171307AAC8 /* FileItemService.swift */; }; 1929B7A2F2B423AA9740FD45 /* FileUtilsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B5D977261F1EBFA9E8F1 /* FileUtilsTest.swift */; }; 1929B93DBAD09835E428F610 /* PrefPane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB251F74BEFC82CEEF84 /* PrefPane.swift */; }; + 1929BA120290D6A2A61A4468 /* ArrayCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B477E1E62433BC48E10B /* ArrayCommonsTest.swift */; }; 1929BCF444CE7F1D14D421DE /* FileItemTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B4778E20696E3AAFB69B /* FileItemTest.swift */; }; 1929BD3F9E609BFADB27584B /* Scorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9D510177918080BE39B /* Scorer.swift */; }; 1929BD4CA2204E061A86A140 /* MatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BC19C1BC19246AFF1621 /* MatcherTests.swift */; }; @@ -262,6 +263,7 @@ 1929B39DA7AC4A9B62D7CD39 /* Component.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Component.swift; sourceTree = ""; }; 1929B3A98687DF171307AAC8 /* FileItemService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemService.swift; sourceTree = ""; }; 1929B4778E20696E3AAFB69B /* FileItemTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemTest.swift; sourceTree = ""; }; + 1929B477E1E62433BC48E10B /* ArrayCommonsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayCommonsTest.swift; sourceTree = ""; }; 1929B5C3F2F1CA4113DABFFD /* CocoaCategories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CocoaCategories.m; sourceTree = ""; }; 1929B5D977261F1EBFA9E8F1 /* FileUtilsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtilsTest.swift; sourceTree = ""; }; 1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemIgnorePattern.swift; sourceTree = ""; }; @@ -755,6 +757,7 @@ 4BF8EEDA1D85903000CAC08A /* PrefUtilsTest.swift */, 1929B41F745CDCDFE09ACDCF /* resources */, 1929B4778E20696E3AAFB69B /* FileItemTest.swift */, + 1929B477E1E62433BC48E10B /* ArrayCommonsTest.swift */, ); path = VimRTests; sourceTree = ""; @@ -1204,6 +1207,7 @@ 1929B7A2F2B423AA9740FD45 /* FileUtilsTest.swift in Sources */, 1929BD4CA2204E061A86A140 /* MatcherTests.swift in Sources */, 1929BCF444CE7F1D14D421DE /* FileItemTest.swift in Sources */, + 1929BA120290D6A2A61A4468 /* ArrayCommonsTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/VimR/FileOutlineView.swift b/VimR/FileOutlineView.swift index ddab356a..76a6d61a 100644 --- a/VimR/FileOutlineView.swift +++ b/VimR/FileOutlineView.swift @@ -104,30 +104,43 @@ class FileOutlineView: NSOutlineView, Flow, NSOutlineViewDataSource, NSOutlineVi self.update(fileBrowserItem) } - fileprivate func update(_ fileBrowserItem: FileBrowserItem) { - let url = fileBrowserItem.fileItem.url - - // Sort the arrays to keep the order. + fileprivate func handleRemovals(for fileBrowserItem: FileBrowserItem, new newChildren: [FileBrowserItem]) { let curChildren = fileBrowserItem.children.sorted() - let newChildren = (self.fileItemService.fileItemWithChildren(for: url)?.children ?? []) - .map(FileBrowserItem.init) - .sorted() let curPreparedChildren = self.prepare(curChildren) let newPreparedChildren = self.prepare(newChildren) - // Handle removals. let childrenToRemoveIndices = curPreparedChildren .enumerated() .filter { newPreparedChildren.contains($0.1) == false } .map { $0.0 } - self.removeItems(at: IndexSet(childrenToRemoveIndices), inParent: fileBrowserItem) + fileBrowserItem.children = curChildren.filter { newChildren.contains($0) } - // Handle additions. + let parent = fileBrowserItem == self.root ? nil : fileBrowserItem + self.removeItems(at: IndexSet(childrenToRemoveIndices), inParent: parent) + } - // Handle children. - let keptChildren = curChildren.filter { newChildren.contains($0) } + fileprivate func handleAdditions(for fileBrowserItem: FileBrowserItem, new newChildren: [FileBrowserItem]) { + let curChildren = fileBrowserItem.children.sorted() + + let curPreparedChildren = self.prepare(curChildren) + let newPreparedChildren = self.prepare(newChildren) + + + + + + + } + + fileprivate func handleChildren(for fileBrowserItem: FileBrowserItem, new newChildren: [FileBrowserItem]) { + let curChildren = fileBrowserItem.children.sorted() + + let curPreparedChildren = self.prepare(curChildren) + let newPreparedChildren = self.prepare(newChildren) + + let keptChildren = curPreparedChildren.filter { newPreparedChildren.contains($0) } // let childrenToAdd = newChildren.filter { curChildren.contains($0) == false } // let resultChildren = childrenToAdd.add(keptChildren) @@ -139,7 +152,20 @@ class FileOutlineView: NSOutlineView, Flow, NSOutlineViewDataSource, NSOutlineVi // self.reloadItem(fileBrowserItem, reloadChildren: false) - childrenToRecurse.forEach(self.update) +// childrenToRecurse.forEach(self.update) + } + + fileprivate func update(_ fileBrowserItem: FileBrowserItem) { + let url = fileBrowserItem.fileItem.url + + // Sort the array to keep the order. + let newChildren = (self.fileItemService.fileItemWithChildren(for: url)?.children ?? []) + .map(FileBrowserItem.init) + .sorted() + + self.handleRemovals(for: fileBrowserItem, new: newChildren) + self.handleAdditions(for: fileBrowserItem, new: newChildren) + self.handleChildren(for: fileBrowserItem, new: newChildren) } fileprivate func fileBrowserItem(with url: URL) -> FileBrowserItem? { diff --git a/VimR/SwiftCommons.swift b/VimR/SwiftCommons.swift index 09cc52d6..9b3d9312 100644 --- a/VimR/SwiftCommons.swift +++ b/VimR/SwiftCommons.swift @@ -14,14 +14,14 @@ extension String { guard self.hasPrefix(prefix) else { return self } - + let idx = self.characters.index(self.startIndex, offsetBy: prefix.characters.count) return self[idx..( - _ chunk: Int = 100, - queue: DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated), - transform: (Element) -> R) -> [R] - { + _ chunk: Int = 100, + queue: DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated), + transform: (Element) -> R) -> [R] { let count = self.count - + let chunkedCount = Int(ceil(Float(count) / Float(chunk))) var result: [[R]] = [] @@ -45,13 +44,32 @@ extension Array { let startIndex = Swift.min(idx * chunk, count) let endIndex = Swift.min(startIndex + chunk, count) - let mappedChunk = self[startIndex.. [Element] { + let elementsInArray = elements.filter { self.contains($0) } + let indices = elementsInArray.map { self.index(of: $0) }.flatMap { $0 } + + var result = self + indices.enumerated().forEach { result[$0.1] = elementsInArray[$0.0] } + + return result + } +} diff --git a/VimRTests/ArrayCommonsTest.swift b/VimRTests/ArrayCommonsTest.swift new file mode 100644 index 00000000..b292d33a --- /dev/null +++ b/VimRTests/ArrayCommonsTest.swift @@ -0,0 +1,154 @@ +/** + * Tae Won Ha - http://taewon.de - @hataewon + * See LICENSE + */ + +import XCTest +import Nimble +@testable import VimR + +fileprivate class DummyToken: Comparable { + + static func ==(left: DummyToken, right: DummyToken) -> Bool { + return left.value == right.value + } + + static func <(left: DummyToken, right: DummyToken) -> Bool { + return left.value < right.value + } + + let value: String + + init(_ value: String) { + self.value = value + } +} + +class ArrayCommonsTest: XCTestCase { + + func testCase1() { + let substitute = [ + DummyToken("a0"), + DummyToken("a1"), + DummyToken("a2") + ] + + let array = [ + DummyToken("b0"), + DummyToken("b1"), + DummyToken("a0"), + DummyToken("a1"), + DummyToken("b4"), + DummyToken("a2"), + ] + + let result = array.substituting(elements: substitute) + + expect(result[2]).to(beIdenticalTo(substitute[0])) + expect(result[3]).to(beIdenticalTo(substitute[1])) + expect(result[5]).to(beIdenticalTo(substitute[2])) + + expect(result).to(equal(array)) + } + + func testCase2() { + let substitute = [ + DummyToken("a0"), + DummyToken("a1"), + DummyToken("a2") + ] + + let array = [ + DummyToken("a0"), + DummyToken("b0"), + DummyToken("a1"), + DummyToken("b1"), + DummyToken("a2"), + DummyToken("b4"), + ] + + let result = array.substituting(elements: substitute) + + expect(result[0]).to(beIdenticalTo(substitute[0])) + expect(result[2]).to(beIdenticalTo(substitute[1])) + expect(result[4]).to(beIdenticalTo(substitute[2])) + + expect(result).to(equal(array)) + } + + func testCase3() { + let substitute = [ + DummyToken("a0"), + DummyToken("a1"), + DummyToken("a2") + ] + + let array = [ + DummyToken("b0"), + DummyToken("b1"), + DummyToken("b4"), + DummyToken("a0"), + DummyToken("a1"), + DummyToken("a2"), + ] + + let result = array.substituting(elements: substitute) + + expect(result[3]).to(beIdenticalTo(substitute[0])) + expect(result[4]).to(beIdenticalTo(substitute[1])) + expect(result[5]).to(beIdenticalTo(substitute[2])) + + expect(result).to(equal(array)) + } + + func testCase4() { + let substitute = [ + DummyToken("a0"), + DummyToken("a1"), + DummyToken("a2") + ] + + let array = [ + DummyToken("a0"), + DummyToken("a1"), + DummyToken("a2"), + DummyToken("b0"), + DummyToken("b1"), + DummyToken("b4"), + ] + + let result = array.substituting(elements: substitute) + + expect(result[0]).to(beIdenticalTo(substitute[0])) + expect(result[1]).to(beIdenticalTo(substitute[1])) + expect(result[2]).to(beIdenticalTo(substitute[2])) + + expect(result).to(equal(array)) + } + + func testCase5() { + let substitute = [ + DummyToken("a0"), + DummyToken("something else"), + DummyToken("a1"), + DummyToken("a2"), + ] + + let array = [ + DummyToken("a0"), + DummyToken("b0"), + DummyToken("a1"), + DummyToken("b1"), + DummyToken("a2"), + DummyToken("b4"), + ] + + let result = array.substituting(elements: substitute) + + expect(result[0]).to(beIdenticalTo(substitute[0])) + expect(result[2]).to(beIdenticalTo(substitute[2])) + expect(result[4]).to(beIdenticalTo(substitute[3])) + + expect(result).to(equal(array)) + } +}