mirror of
https://github.com/qvacua/vimr.git
synced 2024-11-24 03:25:03 +03:00
GH-351 Add substituting to array
This commit is contained in:
parent
bc479d8867
commit
8166f0ec72
@ -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;
|
||||
};
|
||||
|
@ -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? {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
154
VimRTests/ArrayCommonsTest.swift
Normal file
154
VimRTests/ArrayCommonsTest.swift
Normal 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))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user