1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-10-27 18:34:58 +03:00

GH-351 Add substituting to array

This commit is contained in:
Tae Won Ha 2016-11-26 17:59:55 +01:00
parent bc479d8867
commit 8166f0ec72
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
4 changed files with 224 additions and 22 deletions

View File

@ -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 = "<group>"; };
1929B3A98687DF171307AAC8 /* FileItemService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemService.swift; sourceTree = "<group>"; };
1929B4778E20696E3AAFB69B /* FileItemTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemTest.swift; sourceTree = "<group>"; };
1929B477E1E62433BC48E10B /* ArrayCommonsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayCommonsTest.swift; sourceTree = "<group>"; };
1929B5C3F2F1CA4113DABFFD /* CocoaCategories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CocoaCategories.m; sourceTree = "<group>"; };
1929B5D977261F1EBFA9E8F1 /* FileUtilsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtilsTest.swift; sourceTree = "<group>"; };
1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemIgnorePattern.swift; sourceTree = "<group>"; };
@ -755,6 +757,7 @@
4BF8EEDA1D85903000CAC08A /* PrefUtilsTest.swift */,
1929B41F745CDCDFE09ACDCF /* resources */,
1929B4778E20696E3AAFB69B /* FileItemTest.swift */,
1929B477E1E62433BC48E10B /* ArrayCommonsTest.swift */,
);
path = VimRTests;
sourceTree = "<group>";
@ -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;
};

View File

@ -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? {

View File

@ -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..<self.endIndex]
}
}
extension Array {
/// Concurrent and chunked version of `Array.map`.
///
/// - parameters:
@ -30,12 +30,11 @@ extension Array {
/// - transform: The transform function.
/// - returns: Transformed array of `self`.
func concurrentChunkMap<R>(
_ 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..<endIndex].map(transform)
let mappedChunk = self[startIndex ..< endIndex].map(transform)
OSSpinLockLock(&spinLock)
result.append(mappedChunk)
OSSpinLockUnlock(&spinLock)
}
return result.flatMap { $0 }
}
}
extension Array where Element: Equatable {
/**
Returns an array where elements of `elements` contained in the array are substituted by elements of `elements`.
This is useful when you need pointer equality rather than `Equatable`-equality like in `NSOutlineView`.
If an element of `elements` is not contained in the array, it's ignored.
*/
func substituting(elements: [Element]) -> [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
}
}

View File

@ -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))
}
}