1
1
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:
Tae Won Ha 2016-08-30 20:44:58 +02:00
parent 308727a65a
commit d15ee6a2fe
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
17 changed files with 1079 additions and 11 deletions

View File

@ -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
View 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(&param)
}
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(&param)
}
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(&param1, &param2)
}
}
#endif

37
VimR/FileItem.swift Normal file
View 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
}
}

View 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
View 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
View 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!
}
}

View 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
View 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/WagnerFischer_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
View 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
View 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
}
}

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

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

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