mirror of
https://github.com/qvacua/vimr.git
synced 2024-12-24 22:33:52 +03:00
GH-264 Add file items related files and restructure the project a bit
This commit is contained in:
parent
308727a65a
commit
d15ee6a2fe
@ -7,11 +7,32 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1929B0E0C3BC59F52713D5A2 /* FoundationCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */; };
|
||||
1929B10DD8CD7EE0B8BE529F /* Scorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9D510177918080BE39B /* Scorer.swift */; };
|
||||
1929B165820D7177743B537A /* Component.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B39DA7AC4A9B62D7CD39 /* Component.swift */; };
|
||||
1929B1E05C116514C1D3A384 /* CocoaCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 1929B5C3F2F1CA4113DABFFD /* CocoaCategories.m */; };
|
||||
1929B2ADD407219BADBD5A70 /* CwlUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0DD7AE34C049D26DA8C /* CwlUtils.swift */; };
|
||||
1929B2B6F571129EB8D231C5 /* CwlUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0DD7AE34C049D26DA8C /* CwlUtils.swift */; };
|
||||
1929B2E1A64297B8E05BB64A /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA8AC40B901B20F20B71 /* FileUtils.swift */; };
|
||||
1929B3BF1DB87B57559DC27D /* Matcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEEB33113B0E33C3830F /* Matcher.swift */; };
|
||||
1929B3F5743967125F357C9F /* Matcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEEB33113B0E33C3830F /* Matcher.swift */; };
|
||||
1929B43FBA7A31F39D294CD0 /* FileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7CB4863F80230C32D3C /* FileItem.swift */; };
|
||||
1929B462CD4935AFF6D69457 /* FileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7CB4863F80230C32D3C /* FileItem.swift */; };
|
||||
1929B4D3A4429651C2AF55E5 /* FoundationCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */; };
|
||||
1929B53876E6952D378C2B30 /* ScoredFileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */; };
|
||||
1929B6388EAF16C190B82955 /* FileItemIgnorePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */; };
|
||||
1929B63CD9CBB9C122BD99A5 /* ScoredFileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */; };
|
||||
1929B67DA3EB21A631EF1DBB /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA8AC40B901B20F20B71 /* FileUtils.swift */; };
|
||||
1929B728262BAA14FC93F6AC /* NeoVimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BF00B466B40629C2AABE /* NeoVimView.swift */; };
|
||||
1929B73E5EC0B108B83F82EB /* FileItemService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B3A98687DF171307AAC8 /* FileItemService.swift */; };
|
||||
1929B741C4E58EEDAF901353 /* FileItemIgnorePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */; };
|
||||
1929B7A2F2B423AA9740FD45 /* FileUtilsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B5D977261F1EBFA9E8F1 /* FileUtilsTest.swift */; };
|
||||
1929B7C981A0EFCC8D631E3F /* FileItemService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B3A98687DF171307AAC8 /* FileItemService.swift */; };
|
||||
1929B93DBAD09835E428F610 /* PrefPane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB251F74BEFC82CEEF84 /* PrefPane.swift */; };
|
||||
1929BD3F9E609BFADB27584B /* Scorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9D510177918080BE39B /* Scorer.swift */; };
|
||||
1929BD4CA2204E061A86A140 /* MatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BC19C1BC19246AFF1621 /* MatcherTests.swift */; };
|
||||
1929BEB90DCDAF7A2B68C886 /* ColorUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA6128BFDD54CA92F46E /* ColorUtils.swift */; };
|
||||
1929BEFEABA0448306CDB6D4 /* FileItemIgnorePatternTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */; };
|
||||
1929BF81A40B4154D3EA33CE /* server_ui.m in Sources */ = {isa = PBXBuildFile; fileRef = 1929B93013228985F509C8F6 /* server_ui.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
4B029F1A1D45E349004EE0D3 /* PrefWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B029F1C1D45E349004EE0D3 /* PrefWindow.xib */; };
|
||||
4B0BCC941D70320C00D3CE65 /* Logger.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B0BCC931D70320C00D3CE65 /* Logger.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
@ -41,7 +62,7 @@
|
||||
4B56F29D1D29926600C1F92E /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B56F29B1D29926600C1F92E /* Nimble.framework */; };
|
||||
4B570DC21D303CAF006EDC21 /* NeoVimAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B570DC01D303CAF006EDC21 /* NeoVimAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
4B570DC31D303CAF006EDC21 /* NeoVimAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B570DC11D303CAF006EDC21 /* NeoVimAgent.m */; };
|
||||
4B6A70941D60E04200E12030 /* CocoaExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70931D60E04200E12030 /* CocoaExtensions.swift */; };
|
||||
4B6A70941D60E04200E12030 /* AppKitCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70931D60E04200E12030 /* AppKitCommons.swift */; };
|
||||
4B6A70961D6100E300E12030 /* SwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70951D6100E300E12030 /* SwiftCommons.swift */; };
|
||||
4B6A70991D65058A00E12030 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B56F29B1D29926600C1F92E /* Nimble.framework */; };
|
||||
4B6A709C1D6507A000E12030 /* Nimble.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B56F29B1D29926600C1F92E /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
@ -68,6 +89,10 @@
|
||||
4BDF50081D7607BF00D8FBC3 /* EonilFileSystemEvents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BDF50071D7607BF00D8FBC3 /* EonilFileSystemEvents.framework */; };
|
||||
4BDF50091D7607BF00D8FBC3 /* EonilFileSystemEvents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BDF50071D7607BF00D8FBC3 /* EonilFileSystemEvents.framework */; };
|
||||
4BDF500A1D7607C600D8FBC3 /* EonilFileSystemEvents.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4BDF50071D7607BF00D8FBC3 /* EonilFileSystemEvents.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
4BDF500C1D760A3500D8FBC3 /* FileUtilsTest in Resources */ = {isa = PBXBuildFile; fileRef = 4BDF500B1D760A3500D8FBC3 /* FileUtilsTest */; };
|
||||
4BDF500D1D760A6D00D8FBC3 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B2A2BE31D0225800074CE9A /* RxSwift.framework */; };
|
||||
4BDF500E1D760A7500D8FBC3 /* RxSwift.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B2A2BE31D0225800074CE9A /* RxSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
4BDF50121D760B7200D8FBC3 /* EonilFileSystemEvents.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4BDF50071D7607BF00D8FBC3 /* EonilFileSystemEvents.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
4BDF641C1D0887C100D47E1D /* TextDrawer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BDF641A1D0887C100D47E1D /* TextDrawer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
4BDF641D1D0887C100D47E1D /* TextDrawer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BDF641B1D0887C100D47E1D /* TextDrawer.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
4BDF64241D08CAB000D47E1D /* MMCoreTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BDF64221D08CAB000D47E1D /* MMCoreTextView.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
@ -119,6 +144,7 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
4BDF50121D760B7200D8FBC3 /* EonilFileSystemEvents.framework in Embed Frameworks */,
|
||||
4B2A2BFF1D0351810074CE9A /* SwiftNeoVim.framework in Embed Frameworks */,
|
||||
4B2A2BEF1D02261F0074CE9A /* RxSwift.framework in Embed Frameworks */,
|
||||
4B401B161D0454E900D99EDC /* PureLayout.framework in Embed Frameworks */,
|
||||
@ -133,6 +159,7 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
4BDF500E1D760A7500D8FBC3 /* RxSwift.framework in CopyFiles */,
|
||||
4BDF500A1D7607C600D8FBC3 /* EonilFileSystemEvents.framework in CopyFiles */,
|
||||
4B6A709C1D6507A000E12030 /* Nimble.framework in CopyFiles */,
|
||||
);
|
||||
@ -171,14 +198,26 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1929B0DD7AE34C049D26DA8C /* CwlUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CwlUtils.swift; sourceTree = "<group>"; };
|
||||
1929B15B7EDC9B0F40E5E95C /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = "<group>"; };
|
||||
1929B1A51F076E088EF4CCA4 /* server_globals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = server_globals.h; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
1929B7CB4863F80230C32D3C /* FileItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItem.swift; sourceTree = "<group>"; };
|
||||
1929B93013228985F509C8F6 /* server_ui.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = server_ui.m; sourceTree = "<group>"; };
|
||||
1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoundationCommons.swift; sourceTree = "<group>"; };
|
||||
1929B9D510177918080BE39B /* Scorer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scorer.swift; sourceTree = "<group>"; };
|
||||
1929BA6128BFDD54CA92F46E /* ColorUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorUtils.swift; sourceTree = "<group>"; };
|
||||
1929BA8AC40B901B20F20B71 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||
1929BB251F74BEFC82CEEF84 /* PrefPane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefPane.swift; sourceTree = "<group>"; };
|
||||
1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemIgnorePatternTest.swift; sourceTree = "<group>"; };
|
||||
1929BC19C1BC19246AFF1621 /* MatcherTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MatcherTests.swift; sourceTree = "<group>"; };
|
||||
1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScoredFileItem.swift; sourceTree = "<group>"; };
|
||||
1929BE69CF9AB1A10D0DD4F2 /* CocoaCategories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CocoaCategories.h; sourceTree = "<group>"; };
|
||||
1929BEEB33113B0E33C3830F /* Matcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matcher.swift; sourceTree = "<group>"; };
|
||||
1929BF00B466B40629C2AABE /* NeoVimView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NeoVimView.swift; sourceTree = "<group>"; };
|
||||
4B029F1B1D45E349004EE0D3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PrefWindow.xib; sourceTree = "<group>"; };
|
||||
4B0BCC931D70320C00D3CE65 /* Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logger.h; path = VimR/Logger.h; sourceTree = SOURCE_ROOT; };
|
||||
@ -208,7 +247,7 @@
|
||||
4B56F29B1D29926600C1F92E /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/Mac/Nimble.framework; sourceTree = SOURCE_ROOT; };
|
||||
4B570DC01D303CAF006EDC21 /* NeoVimAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NeoVimAgent.h; sourceTree = "<group>"; };
|
||||
4B570DC11D303CAF006EDC21 /* NeoVimAgent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NeoVimAgent.m; sourceTree = "<group>"; };
|
||||
4B6A70931D60E04200E12030 /* CocoaExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CocoaExtensions.swift; sourceTree = "<group>"; };
|
||||
4B6A70931D60E04200E12030 /* AppKitCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppKitCommons.swift; sourceTree = "<group>"; };
|
||||
4B6A70951D6100E300E12030 /* SwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftCommons.swift; sourceTree = "<group>"; };
|
||||
4B854A1A1D31447C00E08DE1 /* NeoVimServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = NeoVimServer; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4B854A1C1D31447C00E08DE1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
@ -230,6 +269,7 @@
|
||||
4BDCFAD41D3145E500F62670 /* libvterm.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvterm.a; path = neovim/.deps/usr/lib/libvterm.a; sourceTree = SOURCE_ROOT; };
|
||||
4BDCFAE91D3147A300F62670 /* NeoVimMsgIds.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NeoVimMsgIds.h; sourceTree = "<group>"; };
|
||||
4BDF50071D7607BF00D8FBC3 /* EonilFileSystemEvents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EonilFileSystemEvents.framework; path = Carthage/Build/Mac/EonilFileSystemEvents.framework; sourceTree = SOURCE_ROOT; };
|
||||
4BDF500B1D760A3500D8FBC3 /* FileUtilsTest */ = {isa = PBXFileReference; lastKnownFileType = folder; path = FileUtilsTest; sourceTree = "<group>"; };
|
||||
4BDF641A1D0887C100D47E1D /* TextDrawer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextDrawer.h; sourceTree = "<group>"; };
|
||||
4BDF641B1D0887C100D47E1D /* TextDrawer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextDrawer.m; sourceTree = "<group>"; };
|
||||
4BDF64221D08CAB000D47E1D /* MMCoreTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMCoreTextView.h; sourceTree = "<group>"; };
|
||||
@ -298,12 +338,21 @@
|
||||
files = (
|
||||
4BDF50091D7607BF00D8FBC3 /* EonilFileSystemEvents.framework in Frameworks */,
|
||||
4B6A70991D65058A00E12030 /* Nimble.framework in Frameworks */,
|
||||
4BDF500D1D760A6D00D8FBC3 /* RxSwift.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
1929B41F745CDCDFE09ACDCF /* resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BDF500B1D760A3500D8FBC3 /* FileUtilsTest */,
|
||||
);
|
||||
path = resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B238BED1D3ED55300CBDD98 /* Preferences */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -418,6 +467,43 @@
|
||||
name = lib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BDF500F1D760A9500D8FBC3 /* UI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1929B39DA7AC4A9B62D7CD39 /* Component.swift */,
|
||||
4BD3BF961D32B0DB00082605 /* MainWindowManager.swift */,
|
||||
4BD3BF921D32A95800082605 /* MainWindowComponent.swift */,
|
||||
4B238BED1D3ED55300CBDD98 /* Preferences */,
|
||||
);
|
||||
name = UI;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BDF50101D760AB700D8FBC3 /* Commons */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B6A70931D60E04200E12030 /* AppKitCommons.swift */,
|
||||
1929B0DD7AE34C049D26DA8C /* CwlUtils.swift */,
|
||||
1929BA8AC40B901B20F20B71 /* FileUtils.swift */,
|
||||
1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */,
|
||||
1929BEEB33113B0E33C3830F /* Matcher.swift */,
|
||||
4BB1BEA81D48773200463C29 /* RxSwiftUtils.swift */,
|
||||
1929B9D510177918080BE39B /* Scorer.swift */,
|
||||
4B6A70951D6100E300E12030 /* SwiftCommons.swift */,
|
||||
);
|
||||
name = Commons;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BDF50111D760B1100D8FBC3 /* File Items */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1929B7CB4863F80230C32D3C /* FileItem.swift */,
|
||||
1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */,
|
||||
1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */,
|
||||
1929B3A98687DF171307AAC8 /* FileItemService.swift */,
|
||||
);
|
||||
name = "File Items";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BEBA4FC1CFF374B00673FDF = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -446,17 +532,13 @@
|
||||
4BEBA5071CFF374B00673FDF /* VimR */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B6A70951D6100E300E12030 /* SwiftCommons.swift */,
|
||||
4B2A2C0D1D0353750074CE9A /* Bridge.h */,
|
||||
4B238BE01D3BF24200CBDD98 /* Application.swift */,
|
||||
4BEBA5081CFF374B00673FDF /* AppDelegate.swift */,
|
||||
1929B39DA7AC4A9B62D7CD39 /* Component.swift */,
|
||||
4BD3BF961D32B0DB00082605 /* MainWindowManager.swift */,
|
||||
4BD3BF921D32A95800082605 /* MainWindowComponent.swift */,
|
||||
4BB1BEA81D48773200463C29 /* RxSwiftUtils.swift */,
|
||||
4B6A70931D60E04200E12030 /* CocoaExtensions.swift */,
|
||||
4B238BED1D3ED55300CBDD98 /* Preferences */,
|
||||
4BDF500F1D760A9500D8FBC3 /* UI */,
|
||||
4BDF50111D760B1100D8FBC3 /* File Items */,
|
||||
4BDF50101D760AB700D8FBC3 /* Commons */,
|
||||
4B97E2CF1D33F92200FC0660 /* resources */,
|
||||
4B2A2C0D1D0353750074CE9A /* Bridge.h */,
|
||||
);
|
||||
path = VimR;
|
||||
sourceTree = "<group>";
|
||||
@ -465,6 +547,10 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BEBA51A1CFF374B00673FDF /* Info.plist */,
|
||||
1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */,
|
||||
1929B5D977261F1EBFA9E8F1 /* FileUtilsTest.swift */,
|
||||
1929BC19C1BC19246AFF1621 /* MatcherTests.swift */,
|
||||
1929B41F745CDCDFE09ACDCF /* resources */,
|
||||
);
|
||||
path = VimRTests;
|
||||
sourceTree = "<group>";
|
||||
@ -682,6 +768,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4BDF500C1D760A3500D8FBC3 /* FileUtilsTest in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -748,7 +835,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4B238BE11D3BF24200CBDD98 /* Application.swift in Sources */,
|
||||
4B6A70941D60E04200E12030 /* CocoaExtensions.swift in Sources */,
|
||||
4B6A70941D60E04200E12030 /* AppKitCommons.swift in Sources */,
|
||||
4BD3BF971D32B0DB00082605 /* MainWindowManager.swift in Sources */,
|
||||
4B238BEC1D3ED54D00CBDD98 /* AppearancePrefPane.swift in Sources */,
|
||||
4BD3BF931D32A95800082605 /* MainWindowComponent.swift in Sources */,
|
||||
@ -760,6 +847,15 @@
|
||||
4BEBA5091CFF374B00673FDF /* AppDelegate.swift in Sources */,
|
||||
1929B165820D7177743B537A /* Component.swift in Sources */,
|
||||
1929B93DBAD09835E428F610 /* PrefPane.swift in Sources */,
|
||||
1929B2ADD407219BADBD5A70 /* CwlUtils.swift in Sources */,
|
||||
1929B462CD4935AFF6D69457 /* FileItem.swift in Sources */,
|
||||
1929B6388EAF16C190B82955 /* FileItemIgnorePattern.swift in Sources */,
|
||||
1929B73E5EC0B108B83F82EB /* FileItemService.swift in Sources */,
|
||||
1929B67DA3EB21A631EF1DBB /* FileUtils.swift in Sources */,
|
||||
1929B3F5743967125F357C9F /* Matcher.swift in Sources */,
|
||||
1929B53876E6952D378C2B30 /* ScoredFileItem.swift in Sources */,
|
||||
1929BD3F9E609BFADB27584B /* Scorer.swift in Sources */,
|
||||
1929B0E0C3BC59F52713D5A2 /* FoundationCommons.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -767,6 +863,18 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1929B2B6F571129EB8D231C5 /* CwlUtils.swift in Sources */,
|
||||
1929B43FBA7A31F39D294CD0 /* FileItem.swift in Sources */,
|
||||
1929B741C4E58EEDAF901353 /* FileItemIgnorePattern.swift in Sources */,
|
||||
1929B7C981A0EFCC8D631E3F /* FileItemService.swift in Sources */,
|
||||
1929B2E1A64297B8E05BB64A /* FileUtils.swift in Sources */,
|
||||
1929B3BF1DB87B57559DC27D /* Matcher.swift in Sources */,
|
||||
1929B63CD9CBB9C122BD99A5 /* ScoredFileItem.swift in Sources */,
|
||||
1929B10DD8CD7EE0B8BE529F /* Scorer.swift in Sources */,
|
||||
1929B4D3A4429651C2AF55E5 /* FoundationCommons.swift in Sources */,
|
||||
1929BEFEABA0448306CDB6D4 /* FileItemIgnorePatternTest.swift in Sources */,
|
||||
1929B7A2F2B423AA9740FD45 /* FileUtilsTest.swift in Sources */,
|
||||
1929BD4CA2204E061A86A140 /* MatcherTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
124
VimR/CwlUtils.swift
Normal file
124
VimR/CwlUtils.swift
Normal file
@ -0,0 +1,124 @@
|
||||
//
|
||||
// CwlMutex.swift
|
||||
// CwlUtils
|
||||
//
|
||||
// Created by Matt Gallagher on 2015/02/03.
|
||||
// Copyright © 2015 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
//
|
||||
|
||||
// Slightly modified by Tae Won Ha
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A basic wrapper around the "NORMAL" and "RECURSIVE" pthread mutex types. This type is a "class" type to take advantage of the "deinit" method.
|
||||
final class PThreadMutex {
|
||||
// Non-recursive "PTHREAD_MUTEX_NORMAL" and recursive "PTHREAD_MUTEX_RECURSIVE" mutex types.
|
||||
enum PThreadMutexType {
|
||||
case Normal
|
||||
case Recursive
|
||||
}
|
||||
|
||||
/// Exposed as an "unsafe" public property so non-scoped patterns can be implemented, if required.
|
||||
private(set) var unsafeMutex = pthread_mutex_t()
|
||||
|
||||
/// Default constructs as ".Normal" or ".Recursive" on request.
|
||||
init(type: PThreadMutexType = .Normal) {
|
||||
var attr = pthread_mutexattr_t()
|
||||
guard pthread_mutexattr_init(&attr) == 0 else {
|
||||
preconditionFailure()
|
||||
}
|
||||
switch type {
|
||||
case .Normal:
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL)
|
||||
case .Recursive:
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)
|
||||
}
|
||||
guard pthread_mutex_init(&unsafeMutex, &attr) == 0 else {
|
||||
preconditionFailure()
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
pthread_mutex_destroy(&unsafeMutex)
|
||||
}
|
||||
|
||||
/* RECOMMENDATION: Don't use the `slowsync` function if you care about performance. Instead, copy this extension into your file and call it:
|
||||
|
||||
extension PThreadMutex {
|
||||
private func sync<R>(@noescape f: () throws -> R) rethrows -> R {
|
||||
pthread_mutex_lock(&unsafeMutex)
|
||||
defer { pthread_mutex_unlock(&unsafeMutex) }
|
||||
return try f()
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
func sync<R>(@noescape f: () throws -> R) rethrows -> R {
|
||||
pthread_mutex_lock(&unsafeMutex)
|
||||
defer { pthread_mutex_unlock(&unsafeMutex) }
|
||||
return try f()
|
||||
}
|
||||
|
||||
/* RECOMMENDATION: Don't use the `trySlowsync` function if you care about performance. Instead, copy this extension into your file and call it:
|
||||
|
||||
extension PThreadMutex {
|
||||
private func trySync<R>(@noescape f: () throws -> R) rethrows -> R? {
|
||||
guard pthread_mutex_trylock(&unsafeMutex) == 0 else { return nil }
|
||||
defer { pthread_mutex_unlock(&unsafeMutex) }
|
||||
return try f()
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
func trySlowsync<R>(@noescape f: () throws -> R) rethrows -> R? {
|
||||
guard pthread_mutex_trylock(&unsafeMutex) == 0 else { return nil }
|
||||
defer { pthread_mutex_unlock(&unsafeMutex) }
|
||||
return try f()
|
||||
}
|
||||
}
|
||||
|
||||
#if PERFORMANCE_TESTS
|
||||
|
||||
/// A basic scoped mutex wrapper around a `dispatch_semaphore_t`.
|
||||
/// For maximum performance, it is recommended that you copy this entire type into the same compilation unit as your code that uses it to ensure inlining.
|
||||
public struct DispatchSemaphore {
|
||||
let s = dispatch_semaphore_create(1)
|
||||
public init() {}
|
||||
public func sync<R>(@noescape f: () throws -> R) rethrows -> R {
|
||||
_ = dispatch_semaphore_wait(s, DISPATCH_TIME_FOREVER)
|
||||
defer { _ = dispatch_semaphore_signal(s) }
|
||||
return try f()
|
||||
}
|
||||
}
|
||||
|
||||
extension PThreadMutex {
|
||||
public func sync_2<T>(inout param: T, @noescape f: (inout T) throws -> Void) rethrows -> Void {
|
||||
pthread_mutex_lock(&unsafeMutex)
|
||||
defer { pthread_mutex_unlock(&unsafeMutex) }
|
||||
try f(¶m)
|
||||
}
|
||||
public func sync_3<T, R>(inout param: T, @noescape f: (inout T) throws -> R) rethrows -> R {
|
||||
pthread_mutex_lock(&unsafeMutex)
|
||||
defer { pthread_mutex_unlock(&unsafeMutex) }
|
||||
return try f(¶m)
|
||||
}
|
||||
public func sync_4<T, U>(inout param1: T, inout _ param2: U, @noescape f: (inout T, inout U) throws -> Void) rethrows -> Void {
|
||||
pthread_mutex_lock(&unsafeMutex)
|
||||
defer { pthread_mutex_unlock(&unsafeMutex) }
|
||||
return try f(¶m1, ¶m2)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
37
VimR/FileItem.swift
Normal file
37
VimR/FileItem.swift
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
class FileItem : CustomStringConvertible {
|
||||
|
||||
let mutex = PThreadMutex()
|
||||
|
||||
let url: NSURL
|
||||
let dir: Bool
|
||||
let hidden: Bool
|
||||
|
||||
/// When nil, then it has never been fnmatch'ed.
|
||||
weak var ignoreToken: Token?
|
||||
var ignore = false
|
||||
|
||||
var needsScanChildren = false
|
||||
var childrenScanned = false
|
||||
|
||||
var children: [FileItem] = []
|
||||
|
||||
var description: String {
|
||||
return "<FileItem: \(self.url), dir=\(self.dir), hidden=\(self.hidden), "
|
||||
+ "needsScan=\(self.needsScanChildren), childrenScanned=\(self.childrenScanned), "
|
||||
+ "ignore=\(self.ignore), ignoreToken=\(self.ignoreToken), "
|
||||
+ "children=\(self.children.count)>"
|
||||
}
|
||||
|
||||
init(_ url: NSURL) {
|
||||
self.url = url
|
||||
self.dir = url.dir
|
||||
self.hidden = url.hidden
|
||||
}
|
||||
}
|
56
VimR/FileItemIgnorePattern.swift
Normal file
56
VimR/FileItemIgnorePattern.swift
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
func ==(lhs: FileItemIgnorePattern, rhs: FileItemIgnorePattern) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
class FileItemIgnorePattern: Hashable {
|
||||
|
||||
var hashValue: Int {
|
||||
return self.pattern.hashValue
|
||||
}
|
||||
|
||||
let folderPattern: Bool
|
||||
let pattern: String
|
||||
|
||||
private let patternAsFileSysRep: UnsafeMutablePointer<Int8>
|
||||
|
||||
init(pattern: String) {
|
||||
self.pattern = pattern
|
||||
self.folderPattern = pattern.hasPrefix("*/")
|
||||
|
||||
let fileSysRep = (pattern as NSString).fileSystemRepresentation
|
||||
let len = Int(strlen(fileSysRep))
|
||||
|
||||
self.patternAsFileSysRep = UnsafeMutablePointer<Int8>.alloc(len + 1)
|
||||
memcpy(self.patternAsFileSysRep, fileSysRep, len)
|
||||
self.patternAsFileSysRep[len] = 0
|
||||
}
|
||||
|
||||
deinit {
|
||||
let len = Int(strlen(self.patternAsFileSysRep))
|
||||
self.patternAsFileSysRep.dealloc(len + 1)
|
||||
}
|
||||
|
||||
func match(absolutePath path: String) -> Bool {
|
||||
let matches: Int32
|
||||
let absolutePath = path as NSString
|
||||
|
||||
if self.folderPattern {
|
||||
matches = fnmatch(self.patternAsFileSysRep,
|
||||
absolutePath.fileSystemRepresentation,
|
||||
FNM_LEADING_DIR | FNM_NOESCAPE)
|
||||
} else {
|
||||
matches = fnmatch(self.patternAsFileSysRep,
|
||||
(absolutePath.lastPathComponent as NSString).fileSystemRepresentation,
|
||||
FNM_NOESCAPE)
|
||||
}
|
||||
|
||||
return matches != FNM_NOMATCH
|
||||
}
|
||||
}
|
203
VimR/FileItemService.swift
Normal file
203
VimR/FileItemService.swift
Normal file
@ -0,0 +1,203 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
import EonilFileSystemEvents
|
||||
|
||||
func == (left: Token, right: Token) -> Bool {
|
||||
return left === right
|
||||
}
|
||||
|
||||
class Token: Equatable {}
|
||||
|
||||
class FileItemService {
|
||||
|
||||
private(set) var ignorePatterns: Set<FileItemIgnorePattern> = [] {
|
||||
didSet {
|
||||
self.ignoreToken = Token()
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to cache fnmatch calls in `FileItem`.
|
||||
private var ignoreToken = Token()
|
||||
|
||||
/// When at least this much of non-directory and visible files are scanned, they are emitted.
|
||||
private let emitChunkSize = 200
|
||||
|
||||
private let scanDispatchQueue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)
|
||||
private let monitorDispatchQueue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)
|
||||
|
||||
private let root = FileItem(NSURL(fileURLWithPath: "/", isDirectory: true))
|
||||
|
||||
private let fileSystemEventsLatency = Double(2)
|
||||
private var monitors = [NSURL: FileSystemEventMonitor]()
|
||||
|
||||
func set(ignorePatterns patterns: Set<FileItemIgnorePattern>) {
|
||||
self.ignorePatterns = patterns
|
||||
}
|
||||
|
||||
func monitor(url url: NSURL) {
|
||||
guard let path = url.path else {
|
||||
return
|
||||
}
|
||||
|
||||
// FIXME: Handle EonilFileSystemEventFlag.RootChanged, ie watchRoot: true
|
||||
let monitor = FileSystemEventMonitor(pathsToWatch: [path],
|
||||
latency: self.fileSystemEventsLatency,
|
||||
watchRoot: false,
|
||||
queue: self.monitorDispatchQueue)
|
||||
{ [unowned self] events in
|
||||
let urls = events.map { NSURL(fileURLWithPath: $0.path) }
|
||||
let parent = FileUtils.commonParent(ofUrls: urls)
|
||||
self.fileItem(forUrl: parent)?.needsScanChildren = true
|
||||
}
|
||||
|
||||
self.monitors[url] = monitor
|
||||
}
|
||||
|
||||
func unmonitor(url url: NSURL) {
|
||||
self.monitors.removeValueForKey(url)
|
||||
}
|
||||
|
||||
func flatFileItems(ofUrl url: NSURL) -> Observable<[FileItem]> {
|
||||
guard url.fileURL else {
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
guard FileUtils.fileExistsAtUrl(url) else {
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
guard let pathComponents = url.pathComponents else {
|
||||
return Observable.empty()
|
||||
}
|
||||
|
||||
return Observable.create { [unowned self] observer in
|
||||
let cancel = AnonymousDisposable {
|
||||
// noop
|
||||
}
|
||||
|
||||
dispatch_async(self.scanDispatchQueue) { [unowned self] in
|
||||
guard let targetItem = self.fileItem(forPathComponents: pathComponents) else {
|
||||
observer.onCompleted()
|
||||
return
|
||||
}
|
||||
|
||||
var flatNewFileItems: [FileItem] = []
|
||||
|
||||
var dirStack: [FileItem] = [targetItem]
|
||||
while let curItem = dirStack.popLast() {
|
||||
if cancel.disposed {
|
||||
observer.onCompleted()
|
||||
return
|
||||
}
|
||||
|
||||
if !curItem.childrenScanned || curItem.needsScanChildren {
|
||||
self.scanChildren(curItem)
|
||||
}
|
||||
|
||||
curItem.children
|
||||
.filter { item in
|
||||
if item.hidden {
|
||||
return false
|
||||
}
|
||||
|
||||
// This item already has been fnmatch'ed, thus return the cached value.
|
||||
if item.ignoreToken == self.ignoreToken {
|
||||
return !item.ignore
|
||||
}
|
||||
|
||||
item.ignoreToken = self.ignoreToken
|
||||
item.ignore = false
|
||||
|
||||
let path = item.url.path!
|
||||
for pattern in self.ignorePatterns {
|
||||
// We don't use `String.FnMatchOption.leadingDir` (`FNM_LEADING_DIR`) for directories since we do not
|
||||
// scan ignored directories at all when filtering. For example "*/.git" would create a `FileItem`
|
||||
// for `/some/path/.git`, but not scan its children when we filter.
|
||||
if pattern.match(absolutePath: path) {
|
||||
item.ignore = true
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
.forEach { $0.dir ? dirStack.append($0) : flatNewFileItems.append($0) }
|
||||
|
||||
if flatNewFileItems.count >= self.emitChunkSize {
|
||||
observer.onNext(flatNewFileItems)
|
||||
flatNewFileItems = []
|
||||
}
|
||||
}
|
||||
|
||||
if !cancel.disposed {
|
||||
observer.onNext(flatNewFileItems)
|
||||
observer.onCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
return cancel
|
||||
}
|
||||
}
|
||||
|
||||
private func fileItem(forUrl url: NSURL) -> FileItem? {
|
||||
guard let pathComponents = url.pathComponents else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return self.fileItem(forPathComponents: pathComponents)
|
||||
}
|
||||
|
||||
/// Returns the `FileItem` corresponding to the `pathComponents` parameter. This is like mkdir -p, i.e. it
|
||||
/// instantiates the intermediate `FileItem`s.
|
||||
///
|
||||
/// - returns: `FileItem` corresponding to `pathComponents`. `nil` if the file does not exist.
|
||||
private func fileItem(forPathComponents pathComponents: [String]) -> FileItem? {
|
||||
let result = pathComponents.dropFirst().reduce(self.root) { (resultItem, childName) -> FileItem? in
|
||||
guard let parent = resultItem else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return self.child(withName: childName, ofParent: parent, create: true)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/// Even when the result is nil it does not mean that there's no child with the given name. It could well be that
|
||||
/// it's not been scanned yet. However, if `create` parameter was true and `nil` is returned, the requested
|
||||
/// child does not exist.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - name: name of the child to get.
|
||||
/// - parent: parent of the child.
|
||||
/// - create: whether to create the child `FileItem` if it's not scanned yet.
|
||||
/// - returns: child `FileItem` or nil.
|
||||
private func child(withName name: String, ofParent parent: FileItem, create: Bool = false) -> FileItem? {
|
||||
let filteredChildren = parent.children.filter { $0.url.lastPathComponent == name }
|
||||
|
||||
if filteredChildren.isEmpty && create {
|
||||
let childUrl = parent.url.URLByAppendingPathComponent(name)
|
||||
|
||||
guard FileUtils.fileExistsAtUrl(childUrl) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let child = FileItem(childUrl)
|
||||
parent.mutex.sync { parent.children.append(child) }
|
||||
return child
|
||||
}
|
||||
|
||||
return filteredChildren.first
|
||||
}
|
||||
|
||||
private func scanChildren(item: FileItem) {
|
||||
item.mutex.sync { item.children = FileUtils.directDescendants(item.url).map(FileItem.init) }
|
||||
item.childrenScanned = true
|
||||
item.needsScanChildren = false
|
||||
}
|
||||
}
|
64
VimR/FileUtils.swift
Normal file
64
VimR/FileUtils.swift
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
class FileUtils {
|
||||
|
||||
private static let keysToGet = [
|
||||
NSURLIsDirectoryKey,
|
||||
NSURLIsHiddenKey,
|
||||
NSURLIsAliasFileKey,
|
||||
NSURLIsSymbolicLinkKey
|
||||
]
|
||||
|
||||
private static let scanOptions: NSDirectoryEnumerationOptions = [
|
||||
NSDirectoryEnumerationOptions.SkipsSubdirectoryDescendants,
|
||||
NSDirectoryEnumerationOptions.SkipsPackageDescendants
|
||||
]
|
||||
|
||||
private static let fileManager = NSFileManager.defaultManager()
|
||||
|
||||
static func directDescendants(url: NSURL) -> [NSURL] {
|
||||
guard let childUrls = try? self.fileManager.contentsOfDirectoryAtURL(
|
||||
url, includingPropertiesForKeys: self.keysToGet, options: self.scanOptions
|
||||
) else {
|
||||
// FIXME error handling
|
||||
return []
|
||||
}
|
||||
|
||||
return childUrls
|
||||
}
|
||||
|
||||
static func fileExistsAtUrl(url: NSURL) -> Bool {
|
||||
guard url.fileURL else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard let path = url.path else {
|
||||
return false
|
||||
}
|
||||
|
||||
return self.fileManager.fileExistsAtPath(path)
|
||||
}
|
||||
|
||||
static func commonParent(ofUrls urls: [NSURL]) -> NSURL {
|
||||
guard urls.count > 0 else {
|
||||
return NSURL(fileURLWithPath: "/", isDirectory: true)
|
||||
}
|
||||
|
||||
let pathComps = urls.map { $0.pathComponents! }
|
||||
let min = pathComps.reduce(pathComps[0].count) { (result, comps) in result < comps.count ? result : comps.count }
|
||||
let pathCompsWithMinCount = pathComps.filter { $0.count == min }
|
||||
let possibleParent = NSURL.fileURLWithPathComponents(pathCompsWithMinCount[0])!
|
||||
|
||||
let minPathComponents = Set(pathComps.map { $0[min - 1] })
|
||||
if minPathComponents.count == 1 {
|
||||
return possibleParent.dir ? possibleParent : possibleParent.URLByDeletingLastPathComponent!
|
||||
}
|
||||
|
||||
return possibleParent.URLByDeletingLastPathComponent!
|
||||
}
|
||||
}
|
75
VimR/FoundationCommons.swift
Normal file
75
VimR/FoundationCommons.swift
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
extension NSURL {
|
||||
|
||||
/// Wrapper function for NSURL.getResourceValue for Bool values.
|
||||
/// Returns also `false` when
|
||||
/// - there is no value for the given `key` or
|
||||
/// - the value cannot be converted to `NSNumber`.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - key: The `key`-parameter of `NSURL.getResourceValue`.
|
||||
func resourceValue(key: String) -> Bool {
|
||||
var rsrc: AnyObject?
|
||||
|
||||
do {
|
||||
try self.getResourceValue(&rsrc, forKey: key)
|
||||
} catch {
|
||||
// FIXME error handling
|
||||
print("\(#function): \(self) -> ERROR while getting \(key)")
|
||||
return false
|
||||
}
|
||||
|
||||
if let result = rsrc as? NSNumber {
|
||||
return result.boolValue
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var dir: Bool {
|
||||
return self.resourceValue(NSURLIsDirectoryKey)
|
||||
}
|
||||
|
||||
var hidden: Bool {
|
||||
return self.resourceValue(NSURLIsHiddenKey)
|
||||
}
|
||||
}
|
||||
|
||||
extension Array {
|
||||
|
||||
/// Concurrent and chunked version of `Array.map`.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - chunk: Batch size; defaults to `100`.
|
||||
/// - queue: Defaults to `dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)`.
|
||||
/// - transform: The transform function.
|
||||
/// - returns: Transformed array of `self`.
|
||||
func concurrentChunkMap<R>(
|
||||
chunk: Int = 100,
|
||||
queue: dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
|
||||
transform: (Element) -> R) -> [R]
|
||||
{
|
||||
let count = self.count
|
||||
|
||||
let chunkedCount = Int(ceil(Float(count) / Float(chunk)))
|
||||
var result: [[R]] = []
|
||||
|
||||
let mutex = PThreadMutex()
|
||||
|
||||
dispatch_apply(chunkedCount, queue) { idx in
|
||||
let startIndex = min(idx * chunk, count)
|
||||
let endIndex = min(startIndex + chunk, count)
|
||||
|
||||
let mappedChunk = self[startIndex..<endIndex].map(transform)
|
||||
mutex.sync { result.append(mappedChunk) }
|
||||
}
|
||||
|
||||
return result.flatMap { $0 }
|
||||
}
|
||||
}
|
142
VimR/Matcher.swift
Normal file
142
VimR/Matcher.swift
Normal file
@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
class Matcher {
|
||||
|
||||
static let uppercaseCharSet = NSCharacterSet.uppercaseLetterCharacterSet()
|
||||
|
||||
enum ExactMatchResult {
|
||||
case none
|
||||
case exact
|
||||
case prefix
|
||||
case suffix
|
||||
case contains
|
||||
}
|
||||
|
||||
static func exactMatchIgnoringCase(target: String, pattern: String) -> ExactMatchResult {
|
||||
let ltarget = target.lowercaseString
|
||||
let lpattern = pattern.lowercaseString
|
||||
if ltarget == lpattern {
|
||||
return .exact
|
||||
}
|
||||
|
||||
if ltarget.hasPrefix(lpattern) {
|
||||
return .prefix
|
||||
}
|
||||
|
||||
if ltarget.hasSuffix(lpattern) {
|
||||
return .suffix
|
||||
}
|
||||
|
||||
if ltarget.containsString(lpattern) {
|
||||
return .contains
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
static func numberOfUppercaseMatches(target: String, pattern: String) -> Int {
|
||||
let tscalars = target.unicodeScalars.filter { uppercaseCharSet.longCharacterIsMember($0.value) }
|
||||
|
||||
guard tscalars.count > 0 else {
|
||||
return 0
|
||||
}
|
||||
|
||||
let pscalars = pattern.uppercaseString.unicodeScalars
|
||||
let pidxStart = pscalars.startIndex
|
||||
let pidx = tscalars.reduce(pidxStart) { pscalars[$0] == $1 ? $0.successor() : $0 }
|
||||
|
||||
return pidxStart.distanceTo(pidx)
|
||||
}
|
||||
|
||||
/// Matches `pattern` to `target` in a fuzzy way.
|
||||
/// - returns: `Array` of `Range<String.UnicodeScalarIndex>`
|
||||
static func fuzzyIgnoringCase(target: String, pattern: String) -> (matches: Int, ranges: [Range<Int>]) {
|
||||
let tlower = target.lowercaseString
|
||||
let plower = pattern.lowercaseString
|
||||
|
||||
let tchars = tlower.unicodeScalars
|
||||
let pchars = plower.unicodeScalars
|
||||
|
||||
var flags = Array(count: tchars.count, repeatedValue: false)
|
||||
|
||||
var pidx = pchars.startIndex
|
||||
for (i, tchar) in tchars.enumerate() {
|
||||
if pchars[pidx] == tchar {
|
||||
flags[i] = true
|
||||
pidx = pidx.successor()
|
||||
}
|
||||
}
|
||||
|
||||
var ranges: [Range<Int>] = []
|
||||
var matches = 0
|
||||
|
||||
var lastTrue = -1
|
||||
var curTrue = -1
|
||||
|
||||
for (i, isTrue) in flags.enumerate() {
|
||||
if isTrue {
|
||||
matches = matches &+ 1
|
||||
if lastTrue == -1 {
|
||||
lastTrue = i
|
||||
}
|
||||
curTrue = i
|
||||
|
||||
if i == flags.count &- 1 {
|
||||
if lastTrue > -1 && curTrue > -1 {
|
||||
ranges.append(lastTrue...curTrue)
|
||||
lastTrue = -1
|
||||
curTrue = -1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if lastTrue > -1 && curTrue > -1 {
|
||||
ranges.append(lastTrue...curTrue)
|
||||
lastTrue = -1
|
||||
curTrue = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (matches, ranges)
|
||||
}
|
||||
|
||||
/// Wagner-Fischer algorithm.
|
||||
/// We use the 32 bit representation (`String.unicodeScalars`) of both parameters to compare them.
|
||||
///
|
||||
/// - returns: the distance of pattern from target
|
||||
/// - seealso: https://en.wikipedia.org/wiki/Wagner–Fischer_algorithm
|
||||
static func wagnerFisherDistance(target: String, pattern: String) -> Int {
|
||||
let s = target.unicodeScalars
|
||||
let t = pattern.unicodeScalars
|
||||
|
||||
let m = s.count
|
||||
|
||||
var prevRow = Array(count: m &+ 1, repeatedValue: 0)
|
||||
var curRow = Array(count: m &+ 1, repeatedValue: 0)
|
||||
|
||||
for i in 0...m {
|
||||
prevRow[i] = i
|
||||
}
|
||||
|
||||
for (j, tchar) in t.enumerate() {
|
||||
curRow[0] = j &+ 1
|
||||
|
||||
for (i, schar) in s.enumerate() {
|
||||
if schar == tchar {
|
||||
curRow[i &+ 1] = prevRow[i]
|
||||
} else {
|
||||
curRow[i &+ 1] = min(curRow[i] &+ 1, prevRow[i &+ 1] &+ 1, prevRow[i] &+ 1)
|
||||
}
|
||||
}
|
||||
|
||||
prevRow = curRow
|
||||
}
|
||||
|
||||
return curRow[m]
|
||||
}
|
||||
}
|
25
VimR/ScoredFileItem.swift
Normal file
25
VimR/ScoredFileItem.swift
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
|
||||
class ScoredFileItem: Comparable {
|
||||
let score: Float
|
||||
let url: NSURL
|
||||
|
||||
init(score: Float, url: NSURL) {
|
||||
self.score = score
|
||||
self.url = url
|
||||
}
|
||||
}
|
||||
|
||||
func == (left: ScoredFileItem, right: ScoredFileItem) -> Bool {
|
||||
return left.score == right.score
|
||||
}
|
||||
|
||||
func <(left: ScoredFileItem, right: ScoredFileItem) -> Bool {
|
||||
return left.score < right.score
|
||||
}
|
31
VimR/Scorer.swift
Normal file
31
VimR/Scorer.swift
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
class Scorer {
|
||||
|
||||
static func score(target: String, pattern: String) -> Float {
|
||||
let wf = Matcher.wagnerFisherDistance(target, pattern: pattern)
|
||||
let fuzzy = Matcher.fuzzyIgnoringCase(target, pattern: pattern)
|
||||
let upper = Matcher.numberOfUppercaseMatches(target, pattern: pattern)
|
||||
let exactMatch = Matcher.exactMatchIgnoringCase(target, pattern: pattern)
|
||||
|
||||
let exactScore: Float
|
||||
switch exactMatch {
|
||||
case .none:
|
||||
exactScore = 0
|
||||
case .exact:
|
||||
return 100
|
||||
case .prefix, .contains, .suffix:
|
||||
exactScore = 5
|
||||
}
|
||||
|
||||
return (wf == 0 ? 0 : 5.0 / Float(wf))
|
||||
+ Float(fuzzy.matches)
|
||||
+ Float(upper)
|
||||
+ exactScore
|
||||
}
|
||||
}
|
64
VimRTests/FileItemIgnorePatternTest.swift
Normal file
64
VimRTests/FileItemIgnorePatternTest.swift
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import XCTest
|
||||
import Nimble
|
||||
|
||||
class FileItemIgnorePatternTest: XCTestCase {
|
||||
|
||||
var pattern: FileItemIgnorePattern = FileItemIgnorePattern(pattern: "dummy")
|
||||
|
||||
func testMatchFolder() {
|
||||
pattern = FileItemIgnorePattern(pattern: "*/.git")
|
||||
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/.git")).to(equal(true))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/.git/d")).to(equal(true))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/.git/d/e")).to(equal(true))
|
||||
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/.gitfolder/d")).to(equal(false))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/1.git/d")).to(equal(false))
|
||||
expect(self.pattern.match(absolutePath: ".git")).to(equal(false))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/.hg/d")).to(equal(false))
|
||||
}
|
||||
|
||||
func testMatchFolderMultipleWildCards() {
|
||||
pattern = FileItemIgnorePattern(pattern: "*/*.xcodeproj")
|
||||
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/VimR.xcodeproj")).to(equal(true))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/VimR.xcodeproj/somefile")).to(equal(true))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/VimR.xcodeproj/somefile/deep")).to(equal(true))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/VimR.xcworkspace/somefile")).to(equal(false))
|
||||
}
|
||||
|
||||
func testMatchSuffix() {
|
||||
pattern = FileItemIgnorePattern(pattern: "*.png")
|
||||
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/d.png")).to(equal(true))
|
||||
expect(self.pattern.match(absolutePath: "a.png")).to(equal(true))
|
||||
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/d.pnge")).to(equal(false))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/d.png/e")).to(equal(false))
|
||||
}
|
||||
|
||||
func testMatchPrefix() {
|
||||
pattern = FileItemIgnorePattern(pattern: "vr*")
|
||||
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/vr.png")).to(equal(true))
|
||||
expect(self.pattern.match(absolutePath: "vr.png")).to(equal(true))
|
||||
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/wvr.png")).to(equal(false))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/wvr.png/e")).to(equal(false))
|
||||
}
|
||||
|
||||
func testMatchExact() {
|
||||
pattern = FileItemIgnorePattern(pattern: "some")
|
||||
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/some")).to(equal(true))
|
||||
expect(self.pattern.match(absolutePath: "some")).to(equal(true))
|
||||
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/some1")).to(equal(false))
|
||||
expect(self.pattern.match(absolutePath: "/a/b/c/1some")).to(equal(false))
|
||||
}
|
||||
}
|
89
VimRTests/FileUtilsTest.swift
Normal file
89
VimRTests/FileUtilsTest.swift
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import XCTest
|
||||
import Nimble
|
||||
|
||||
class FileUtilsTest: XCTestCase {
|
||||
|
||||
var fileUtilsRsrcUrl = NSURL()
|
||||
var a1Dir = NSURL()
|
||||
|
||||
override func setUp() {
|
||||
fileUtilsRsrcUrl = NSBundle.init(forClass: self.dynamicType).URLForResource("FileUtilsTest", withExtension: "")!
|
||||
a1Dir = fileUtilsRsrcUrl.URLByAppendingPathComponent("a1")
|
||||
}
|
||||
|
||||
func testCommonParentOneDirUrl() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
}
|
||||
|
||||
func testCommonParentOneFileUrl() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
}
|
||||
|
||||
func testCommonParentEmptyParams() {
|
||||
expect(FileUtils.commonParent(ofUrls: [])).to(equal(NSURL(fileURLWithPath: "/", isDirectory: true)))
|
||||
}
|
||||
|
||||
func testCommonParent1() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
}
|
||||
|
||||
func testCommonParent2() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
}
|
||||
|
||||
func testCommonParent3() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("b1/b1-file1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(fileUtilsRsrcUrl))
|
||||
}
|
||||
|
||||
func testCommonParent4() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("b1"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(fileUtilsRsrcUrl))
|
||||
}
|
||||
|
||||
func testCommonParent5() {
|
||||
let urls = [
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a1-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2/a1-a2-file1"),
|
||||
fileUtilsRsrcUrl.URLByAppendingPathComponent("a1/a2"),
|
||||
]
|
||||
|
||||
expect(FileUtils.commonParent(ofUrls: urls)).to(equal(a1Dir))
|
||||
}
|
||||
}
|
50
VimRTests/MatcherTests.swift
Normal file
50
VimRTests/MatcherTests.swift
Normal file
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import XCTest
|
||||
import Nimble
|
||||
|
||||
class MatcherTest: XCTestCase {
|
||||
|
||||
let target = "UserDefaultContextTest.swift"
|
||||
|
||||
func testFnmatch() {
|
||||
expect(fnmatch(
|
||||
".git".cStringUsingEncoding(NSUTF8StringEncoding),
|
||||
"/test/.git".cStringUsingEncoding(NSUTF8StringEncoding),
|
||||
0)
|
||||
)
|
||||
.to(equal(FNM_NOMATCH))
|
||||
}
|
||||
|
||||
func testExactMatch() {
|
||||
expect(Matcher.exactMatchIgnoringCase(self.target, pattern: "uSERdEFAULTcONTEXTtEST.SWIFT"))
|
||||
.to(equal(Matcher.ExactMatchResult.exact))
|
||||
expect(Matcher.exactMatchIgnoringCase(self.target, pattern: "uSERdEFAULt"))
|
||||
.to(equal(Matcher.ExactMatchResult.prefix))
|
||||
expect(Matcher.exactMatchIgnoringCase(self.target, pattern: "swIFt")).to(equal(Matcher.ExactMatchResult.suffix))
|
||||
expect(Matcher.exactMatchIgnoringCase(self.target, pattern: "userdecon")).to(equal(Matcher.ExactMatchResult.none))
|
||||
}
|
||||
|
||||
func testUppercaseMatcher() {
|
||||
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "xct")).to(equal(0))
|
||||
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "uct")).to(equal(3))
|
||||
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "uDcT")).to(equal(4))
|
||||
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "dct")).to(equal(3))
|
||||
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "ut")).to(equal(2))
|
||||
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "de")).to(equal(1))
|
||||
}
|
||||
|
||||
func testFuzzyMatcher() {
|
||||
expect(Matcher.fuzzyIgnoringCase(self.target, pattern: "ucotft").matches).to(equal(6))
|
||||
expect(Matcher.fuzzyIgnoringCase(self.target, pattern: "uco-tft").matches).to(equal(3))
|
||||
}
|
||||
|
||||
func testWagerFischerAlgo() {
|
||||
expect(Matcher.wagnerFisherDistance("sitting", pattern: "kitten")).to(equal(3))
|
||||
expect(Matcher.wagnerFisherDistance("saturday", pattern: "sunday")).to(equal(3))
|
||||
expect(Matcher.wagnerFisherDistance("하태원", pattern: "하태이")).to(equal(1))
|
||||
}
|
||||
}
|
0
VimRTests/resources/FileUtilsTest/a1/a1-file1
Normal file
0
VimRTests/resources/FileUtilsTest/a1/a1-file1
Normal file
0
VimRTests/resources/FileUtilsTest/a1/a2/a1-a2-file1
Normal file
0
VimRTests/resources/FileUtilsTest/a1/a2/a1-a2-file1
Normal file
0
VimRTests/resources/FileUtilsTest/b1/b1-file1
Normal file
0
VimRTests/resources/FileUtilsTest/b1/b1-file1
Normal file
Loading…
Reference in New Issue
Block a user