diff options
Diffstat (limited to 'mut')
| -rw-r--r-- | mut/keuze/.gitignore | 63 | ||||
| -rw-r--r-- | mut/keuze/README.md | 44 | ||||
| -rw-r--r-- | mut/keuze/keuze.xcodeproj/project.pbxproj | 353 | ||||
| -rw-r--r-- | mut/keuze/keuze.xcodeproj/project.xcworkspace/contents.xcworkspacedata | 7 | ||||
| -rw-r--r-- | mut/keuze/keuze.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist | 8 | ||||
| -rw-r--r-- | mut/keuze/keuze.xcodeproj/xcshareddata/xcschemes/kies.xcscheme | 97 | ||||
| -rw-r--r-- | mut/keuze/kies/DataSource.swift | 43 | ||||
| -rw-r--r-- | mut/keuze/kies/Info.plist | 32 | ||||
| -rw-r--r-- | mut/keuze/kies/InputField.swift | 67 | ||||
| -rw-r--r-- | mut/keuze/kies/Layout.swift | 44 | ||||
| -rw-r--r-- | mut/keuze/kies/PromptText.swift | 28 | ||||
| -rw-r--r-- | mut/keuze/kies/Settings.swift | 48 | ||||
| -rw-r--r-- | mut/keuze/kies/SwiftLCS.swift | 268 | ||||
| -rw-r--r-- | mut/keuze/kies/TableView.swift | 89 | ||||
| -rw-r--r-- | mut/keuze/kies/Window.swift | 51 | ||||
| -rw-r--r-- | mut/keuze/kies/constants.swift | 13 | ||||
| -rw-r--r-- | mut/keuze/kies/main.swift | 132 | ||||
| -rw-r--r-- | mut/keuze/screenshots/screenshot1.png | bin | 0 -> 2922865 bytes |
18 files changed, 1387 insertions, 0 deletions
diff --git a/mut/keuze/.gitignore b/mut/keuze/.gitignore new file mode 100644 index 0000000..09dfede --- /dev/null +++ b/mut/keuze/.gitignore @@ -0,0 +1,63 @@ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ diff --git a/mut/keuze/README.md b/mut/keuze/README.md new file mode 100644 index 0000000..05fda20 --- /dev/null +++ b/mut/keuze/README.md @@ -0,0 +1,44 @@ +# Keuze +Universal fuzzy selector for macOs comparable with dmenu. + + + +- Gets list of items from stdin. +- Sorts choices as you type. +- Sends result to stdout. + +## Install + +1. Download the latest release (or build it) +2. Place it in your path + +## Basic Usage + +```bash +$ alias keuze="keuze -fs 12 -fn Monaco" +$ ls | keuze -p "list" +``` + +## License + +> Released under MIT license. +> +> Copyright (c) 2019 Thomas Billiet +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. diff --git a/mut/keuze/keuze.xcodeproj/project.pbxproj b/mut/keuze/keuze.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5292f7b --- /dev/null +++ b/mut/keuze/keuze.xcodeproj/project.pbxproj @@ -0,0 +1,353 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 90281C6D225F763100236C8B /* DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90281C6C225F763100236C8B /* DataSource.swift */; }; + 90281C7D2262925500236C8B /* SwiftLCS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90281C7C2262925500236C8B /* SwiftLCS.swift */; }; + 90281C7F2263539A00236C8B /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90281C7E2263539A00236C8B /* Settings.swift */; }; + 90281C8122635C7100236C8B /* Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90281C8022635C7100236C8B /* Layout.swift */; }; + 90537621225B89E2003B4D25 /* constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90537620225B89E2003B4D25 /* constants.swift */; }; + 90537627225B8EDA003B4D25 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90537626225B8EDA003B4D25 /* main.swift */; }; + 90537629225B95DB003B4D25 /* PromptText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90537628225B95DB003B4D25 /* PromptText.swift */; }; + 9053762B225BA282003B4D25 /* InputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9053762A225BA282003B4D25 /* InputField.swift */; }; + 9053762D225BEA61003B4D25 /* TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9053762C225BEA61003B4D25 /* TableView.swift */; }; + 90EB57CA225B83BC002E81D7 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90EB57C9225B83BC002E81D7 /* AppKit.framework */; }; + 90EB57CC225B83C2002E81D7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90EB57CB225B83C2002E81D7 /* Foundation.framework */; }; + 90EB57CE225B83CB002E81D7 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90EB57CD225B83CB002E81D7 /* Cocoa.framework */; }; + 90EB57D0225B8742002E81D7 /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90EB57CF225B8742002E81D7 /* Window.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 90281C6C225F763100236C8B /* DataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataSource.swift; sourceTree = "<group>"; }; + 90281C7C2262925500236C8B /* SwiftLCS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftLCS.swift; sourceTree = "<group>"; }; + 90281C7E2263539A00236C8B /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; }; + 90281C8022635C7100236C8B /* Layout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Layout.swift; sourceTree = "<group>"; }; + 90537620225B89E2003B4D25 /* constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = constants.swift; sourceTree = "<group>"; }; + 90537626225B8EDA003B4D25 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; }; + 90537628225B95DB003B4D25 /* PromptText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PromptText.swift; sourceTree = "<group>"; }; + 9053762A225BA282003B4D25 /* InputField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputField.swift; sourceTree = "<group>"; }; + 9053762C225BEA61003B4D25 /* TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableView.swift; sourceTree = "<group>"; }; + 90EB57C9225B83BC002E81D7 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 90EB57CB225B83C2002E81D7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 90EB57CD225B83CB002E81D7 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 90EB57CF225B8742002E81D7 /* Window.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Window.swift; sourceTree = "<group>"; }; + EF3CE234203361F2000CAD87 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + EF3CE235203361F2000CAD87 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; + EF860B222034C4D50087C40D /* head.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = head.h; sourceTree = "<group>"; }; + EFEAA7E6203393C200FB0263 /* keuze */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = keuze; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + EFEAA7E3203393C200FB0263 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 90EB57CE225B83CB002E81D7 /* Cocoa.framework in Frameworks */, + 90EB57CC225B83C2002E81D7 /* Foundation.framework in Frameworks */, + 90EB57CA225B83BC002E81D7 /* AppKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 90EB57C8225B83BB002E81D7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 90EB57CD225B83CB002E81D7 /* Cocoa.framework */, + 90EB57CB225B83C2002E81D7 /* Foundation.framework */, + 90EB57C9225B83BC002E81D7 /* AppKit.framework */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; + EF3CE220203361F2000CAD87 = { + isa = PBXGroup; + children = ( + EF3CE22B203361F2000CAD87 /* kies */, + EF3CE22A203361F2000CAD87 /* Products */, + 90EB57C8225B83BB002E81D7 /* Frameworks */, + ); + sourceTree = "<group>"; + }; + EF3CE22A203361F2000CAD87 /* Products */ = { + isa = PBXGroup; + children = ( + EFEAA7E6203393C200FB0263 /* keuze */, + ); + name = Products; + sourceTree = "<group>"; + }; + EF3CE22B203361F2000CAD87 /* kies */ = { + isa = PBXGroup; + children = ( + EF3CE234203361F2000CAD87 /* Info.plist */, + EF3CE235203361F2000CAD87 /* main.m */, + EF860B222034C4D50087C40D /* head.h */, + 90537626225B8EDA003B4D25 /* main.swift */, + 90EB57CF225B8742002E81D7 /* Window.swift */, + 90537620225B89E2003B4D25 /* constants.swift */, + 90537628225B95DB003B4D25 /* PromptText.swift */, + 9053762A225BA282003B4D25 /* InputField.swift */, + 9053762C225BEA61003B4D25 /* TableView.swift */, + 90281C6C225F763100236C8B /* DataSource.swift */, + 90281C7C2262925500236C8B /* SwiftLCS.swift */, + 90281C7E2263539A00236C8B /* Settings.swift */, + 90281C8022635C7100236C8B /* Layout.swift */, + ); + path = kies; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + EFEAA7E5203393C200FB0263 /* keuze */ = { + isa = PBXNativeTarget; + buildConfigurationList = EFEAA7EC203393C200FB0263 /* Build configuration list for PBXNativeTarget "keuze" */; + buildPhases = ( + EFEAA7E2203393C200FB0263 /* Sources */, + EFEAA7E3203393C200FB0263 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = keuze; + productName = kies; + productReference = EFEAA7E6203393C200FB0263 /* keuze */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + EF3CE221203361F2000CAD87 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Thomas Billiet"; + TargetAttributes = { + EFEAA7E5203393C200FB0263 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1020; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = EF3CE224203361F2000CAD87 /* Build configuration list for PBXProject "keuze" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = EF3CE220203361F2000CAD87; + productRefGroup = EF3CE22A203361F2000CAD87 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + EFEAA7E5203393C200FB0263 /* keuze */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + EFEAA7E2203393C200FB0263 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 90EB57D0225B8742002E81D7 /* Window.swift in Sources */, + 9053762D225BEA61003B4D25 /* TableView.swift in Sources */, + 90281C6D225F763100236C8B /* DataSource.swift in Sources */, + 90281C7D2262925500236C8B /* SwiftLCS.swift in Sources */, + 90537621225B89E2003B4D25 /* constants.swift in Sources */, + 90537629225B95DB003B4D25 /* PromptText.swift in Sources */, + 90281C7F2263539A00236C8B /* Settings.swift in Sources */, + 90281C8122635C7100236C8B /* Layout.swift in Sources */, + 9053762B225BA282003B4D25 /* InputField.swift in Sources */, + 90537627225B8EDA003B4D25 /* main.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + EF3CE238203361F2000CAD87 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + EF3CE239203361F2000CAD87 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + EFEAA7EA203393C200FB0263 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "$(SRCROOT)/kies/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks @loader_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ""; + MACOSX_DEPLOYMENT_TARGET = 10.13; + OTHER_LDFLAGS = ( + "-sectcreate", + __TEXT, + __info_plist, + "$(SRCROOT)/kies/Info.plist", + "-rpath", + $DT_TOOLCHAIN_DIR/usr/lib/swift/macosx/, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VALID_ARCHS = x86_64; + }; + name = Debug; + }; + EFEAA7EB203393C200FB0263 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "$(SRCROOT)/kies/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks @loader_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ""; + MACOSX_DEPLOYMENT_TARGET = 10.13; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + VALID_ARCHS = x86_64; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + EF3CE224203361F2000CAD87 /* Build configuration list for PBXProject "keuze" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EF3CE238203361F2000CAD87 /* Debug */, + EF3CE239203361F2000CAD87 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EFEAA7EC203393C200FB0263 /* Build configuration list for PBXNativeTarget "keuze" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EFEAA7EA203393C200FB0263 /* Debug */, + EFEAA7EB203393C200FB0263 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = EF3CE221203361F2000CAD87 /* Project object */; +} diff --git a/mut/keuze/keuze.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mut/keuze/keuze.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..ccb0550 --- /dev/null +++ b/mut/keuze/keuze.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:/Users/thomasbilliet/Projects/kies/keuze.xcodeproj"> + </FileRef> +</Workspace> diff --git a/mut/keuze/keuze.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mut/keuze/keuze.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/mut/keuze/keuze.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>IDEDidComputeMac32BitWarning</key> + <true/> +</dict> +</plist> diff --git a/mut/keuze/keuze.xcodeproj/xcshareddata/xcschemes/kies.xcscheme b/mut/keuze/keuze.xcodeproj/xcshareddata/xcschemes/kies.xcscheme new file mode 100644 index 0000000..8c95d67 --- /dev/null +++ b/mut/keuze/keuze.xcodeproj/xcshareddata/xcschemes/kies.xcscheme @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "1020" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "EFEAA7E5203393C200FB0263" + BuildableName = "keuze" + BlueprintName = "keuze" + ReferencedContainer = "container:keuze.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "EFEAA7E5203393C200FB0263" + BuildableName = "keuze" + BlueprintName = "keuze" + ReferencedContainer = "container:keuze.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "EFEAA7E5203393C200FB0263" + BuildableName = "keuze" + BlueprintName = "keuze" + ReferencedContainer = "container:keuze.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + <CommandLineArguments> + <CommandLineArgument + argument = "" + isEnabled = "NO"> + </CommandLineArgument> + </CommandLineArguments> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "EFEAA7E5203393C200FB0263" + BuildableName = "keuze" + BlueprintName = "keuze" + ReferencedContainer = "container:keuze.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/mut/keuze/kies/DataSource.swift b/mut/keuze/kies/DataSource.swift new file mode 100644 index 0000000..23c1f8e --- /dev/null +++ b/mut/keuze/kies/DataSource.swift @@ -0,0 +1,43 @@ +// +// Sorter.swift +// kies +// +// Created by Thomas Billiet on 11/04/2019. +// Copyright © 2019 Thomas Billiet. All rights reserved. +// + +import Foundation +import Cocoa + +class DataSource: NSObject, NSTableViewDataSource { + var items = [String]() + var sortedItems = [String]() + var matches = [String: String]() + var scores = [String: Float]() + + func updateItems(_ items: [String]) { + self.items = items + self.sortedItems = items + } + + func updateSort(query: String) { + for item in items { + let match = item.lowercased().longestCommonSubsequence(query.lowercased()) + matches[item] = match + scores[item] = Float(match.count) / Float(query.count) + } + + sortedItems = items.sorted(by: { (a, b) -> Bool in + scores[a]! > scores[b]! + }) + } + + func numberOfRows(in tableView: NSTableView) -> Int { + return sortedItems.count + } + + func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { + return sortedItems[row] + } + +} diff --git a/mut/keuze/kies/Info.plist b/mut/keuze/kies/Info.plist new file mode 100644 index 0000000..bfedb9a --- /dev/null +++ b/mut/keuze/kies/Info.plist @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>$(DEVELOPMENT_LANGUAGE)</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIconFile</key> + <string></string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> + <key>LSApplicationCategoryType</key> + <string>public.app-category.productivity</string> + <key>LSMinimumSystemVersion</key> + <string>$(MACOSX_DEPLOYMENT_TARGET)</string> + <key>NSHumanReadableCopyright</key> + <string>Copyright © 2019 Thomas Billiet. All rights reserved.</string> + <key>NSPrincipalClass</key> + <string>NSApplication</string> +</dict> +</plist> diff --git a/mut/keuze/kies/InputField.swift b/mut/keuze/kies/InputField.swift new file mode 100644 index 0000000..6e8e27c --- /dev/null +++ b/mut/keuze/kies/InputField.swift @@ -0,0 +1,67 @@ +// +// KiesInputField.swift +// kies +// +// Created by Thomas Billiet on 08/04/2019. +// Copyright © 2019 Thomas Billiet. All rights reserved. +// + +import Foundation +import Cocoa + +class InputField: NSTextField, NSTextFieldDelegate { + var appDelegate: AppDelegate! + + init(appDelegate: AppDelegate) { + super.init(frame: layouts.inputRect) + self.appDelegate = appDelegate + stringValue = "" + isEditable = true + isSelectable = true + delegate = self + bezelStyle = .squareBezel + isBordered = false + drawsBackground = false + focusRingType = .none + target = self + font = settings.font + allowsEditingTextAttributes = false + isAutomaticTextCompletionEnabled = false + allowsDefaultTighteningForTruncation = false + maximumNumberOfLines = 1 + cell?.wraps = false + cell?.isScrollable = true + autoresizingMask = [NSView.AutoresizingMask.width] + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool { + if (commandSelector == #selector(NSStandardKeyBindingResponding.cancelOperation(_:))){ + appDelegate.cancel() + return true + } + if (commandSelector == #selector(NSStandardKeyBindingResponding.insertNewline(_:))){ + appDelegate.handleSelect() + return true + } + if (commandSelector == #selector(NSStandardKeyBindingResponding.moveUp(_:))){ + appDelegate.handleMoveUp() + return true + } + if (commandSelector == #selector(NSStandardKeyBindingResponding.moveDown(_:))){ + appDelegate.handleMoveDown() + return true + } + if (commandSelector == #selector(NSStandardKeyBindingResponding.insertTab(_:))){ + return true + } + return false + } + + func controlTextDidChange(_ obj: Notification) { + appDelegate.handleInputChange(input: stringValue) + } +} diff --git a/mut/keuze/kies/Layout.swift b/mut/keuze/kies/Layout.swift new file mode 100644 index 0000000..cf04eb0 --- /dev/null +++ b/mut/keuze/kies/Layout.swift @@ -0,0 +1,44 @@ +// +// Layout.swift +// keuze +// +// Created by Thomas Billiet on 14/04/2019. +// Copyright © 2019 Thomas Billiet. All rights reserved. +// + +import Foundation + +class Layout { + let DIVIDER_HEIGHT: CGFloat = 9 + + var lineHeight: CGFloat { + return ceil(NSString(string: "TEST").size(withAttributes: [.font: settings.font]).height) + 0; + } + + var windowRect: NSRect { + return NSMakeRect(0, 0, settings.windowWidth, settings.windowHeight) + } + + var containerRect: NSRect { + return NSMakeRect(settings.windowPadding, settings.windowPadding, windowRect.width - settings.windowPadding * 2, windowRect.height - settings.windowPadding * 2) + } + + var listRect: NSRect { + return NSMakeRect(containerRect.minX, containerRect.minY, containerRect.width, containerRect.height - lineHeight - DIVIDER_HEIGHT) + } + + var dividerRect: NSRect { + return NSMakeRect(containerRect.minX, listRect.maxY + DIVIDER_HEIGHT / 2, containerRect.width, 1) + } + + var promptRect: NSRect { + let stringWidth = ceil(NSString(string: settings.promptText!).size(withAttributes: [.font: settings.font]).width) + 4; + return NSMakeRect(containerRect.minX, containerRect.maxY - lineHeight, stringWidth, lineHeight) + } + + var inputRect: NSRect { + return NSMakeRect(promptRect.maxX, containerRect.maxY - lineHeight, containerRect.width - promptRect.width, lineHeight) + } +} + +let layouts = Layout() diff --git a/mut/keuze/kies/PromptText.swift b/mut/keuze/kies/PromptText.swift new file mode 100644 index 0000000..7cd6750 --- /dev/null +++ b/mut/keuze/kies/PromptText.swift @@ -0,0 +1,28 @@ +// +// KiesPromptText.swift +// kies +// +// Created by Thomas Billiet on 08/04/2019. +// Copyright © 2019 Thomas Billiet. All rights reserved. +// + +import Foundation +import Cocoa + +class PromptText: NSTextField { + init(text: String) { + super.init(frame: layouts.promptRect) + stringValue = text + isEditable = false + drawsBackground = false + isSelectable = false + bezelStyle = .squareBezel + font = settings.font + isBordered = false + autoresizingMask = [NSView.AutoresizingMask.width] + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/mut/keuze/kies/Settings.swift b/mut/keuze/kies/Settings.swift new file mode 100644 index 0000000..ab2c3df --- /dev/null +++ b/mut/keuze/kies/Settings.swift @@ -0,0 +1,48 @@ +// +// Settings.swift +// keuze +// +// Created by Thomas Billiet on 14/04/2019. +// Copyright © 2019 Thomas Billiet. All rights reserved. +// + +import Foundation +import Cocoa + +class Settings { + + var promptText: String? { + var prompt = UserDefaults.standard.string(forKey: "p") + if (prompt != nil) { + prompt = prompt! + ":" + } + return prompt + } + + var font: NSFont? { + let fn = UserDefaults.standard.string(forKey: "fn") + let fs = UserDefaults.standard.integer(forKey: "fs") + let fontSize = fs == 0 ? 14 : CGFloat(fs) + if (fn == nil) { + return NSFont.systemFont(ofSize: fontSize) + } + return NSFont(name: fn!, size: fontSize) + } + + var windowPadding: CGFloat { + let val = UserDefaults.standard.integer(forKey: "pd") + return val == 0 ? 12 : CGFloat(val) + } + + var windowHeight: CGFloat { + let val = UserDefaults.standard.integer(forKey: "h") + return val == 0 ? 310 : CGFloat(val) + } + + var windowWidth: CGFloat { + let val = UserDefaults.standard.integer(forKey: "w") + return val == 0 ? 500 : CGFloat(val) + } +} + +let settings = Settings() diff --git a/mut/keuze/kies/SwiftLCS.swift b/mut/keuze/kies/SwiftLCS.swift new file mode 100644 index 0000000..2587c93 --- /dev/null +++ b/mut/keuze/kies/SwiftLCS.swift @@ -0,0 +1,268 @@ +// +// The MIT License (MIT) +// +// Copyright (c) 2015 Tommaso Madonia +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +import Foundation + +/** + A generic struct that represents a diff between two collections. + */ +public struct Diff<Index> { + + /// The indexes whose corresponding values in the old collection are in the LCS. + public var commonIndexes: [Index] { + return self._commonIndexSet.indexes + } + + /// The indexes whose corresponding values in the new collection are not in the LCS. + public var addedIndexes: [Index] { + return self._addedIndexSet.indexes + } + + /// The indexes whose corresponding values in the old collection are not in the LCS. + public var removedIndexes: [Index] { + return self._removedIndexSet.indexes + } + + /// Construct the `Diff` between two given collections. + public init<C: Collection>(_ old: C, _ new: C) where C.Index == Index, C.Element: Equatable { + self = old.diff(new) + } + + fileprivate let _commonIndexSet: DiffIndexSet<Index> + fileprivate let _addedIndexSet: DiffIndexSet<Index> + fileprivate let _removedIndexSet: DiffIndexSet<Index> + + fileprivate init(commonIndexes: DiffIndexSet<Index>, addedIndexes: DiffIndexSet<Index>, removedIndexes: DiffIndexSet<Index>) { + self._commonIndexSet = commonIndexes + self._addedIndexSet = addedIndexes + self._removedIndexSet = removedIndexes + } + +} + +/** + An extension of `Diff`, which adds support for `IndexSet`. + */ +public extension Diff where Index: Strideable, Index.Stride: SignedInteger { + + /// The indexes whose corresponding values in the old collection are in the LCS. + var commonIndexSet: IndexSet { + return self._commonIndexSet.indexSet + } + + /// The indexes whose corresponding values in the new collection are not in the LCS. + var addedIndexSet: IndexSet { + return self._addedIndexSet.indexSet + } + + /// The indexes whose corresponding values in the old collection are not in the LCS. + var removedIndexSet: IndexSet { + return self._removedIndexSet.indexSet + } + +} + +private struct DiffIndexSet<Index> { + + let startIndex: Index + let indexes: [Index] + + init(_ indexes: [Index], startIndex: Index) { + self.indexes = indexes + self.startIndex = startIndex + } + +} + +private extension DiffIndexSet where Index: Strideable, Index.Stride: SignedInteger { + + var indexSet: IndexSet { + let indexes = self.indexes.map { Int((self.startIndex..<$0).count) } + + return IndexSet(indexes) + } + +} + +// MARK: - +/** + An extension of `Collection`, which calculates the diff between two collections. + */ +public extension Collection where Element: Equatable { + + /** + Returns the diff between two collections. + + - complexity: O(mn) where `m` and `n` are the lengths of the receiver and the given collection. + - parameter collection: The collection with which to compare the receiver. + - returns: The diff between the receiver and the given collection. + */ + func diff(_ otherCollection: Self) -> Diff<Index> { + let count = self.count + let commonIndexes = self.longestCommonSubsequence(otherCollection, selfCount: count) + + var removedIndexes: [Index] = [] + removedIndexes.reserveCapacity(count - commonIndexes.count) + + var addedIndexes: [Index] = [] + + var index = self.startIndex + var otherIndex = otherCollection.startIndex + var commonIndexesIterator = commonIndexes.makeIterator() + var commonIndex = commonIndexesIterator.next() + while index != self.endIndex { + if commonIndex == index { + commonIndex = commonIndexesIterator.next() + + while otherIndex != otherCollection.endIndex && otherCollection[otherIndex] != self[index] { + addedIndexes.append(otherIndex) + otherIndex = otherCollection.index(after: otherIndex) + } + + if otherIndex != otherCollection.endIndex { + otherIndex = otherCollection.index(after: otherIndex) + } + } else { + removedIndexes.append(index) + } + + index = self.index(after: index) + } + + while otherIndex != otherCollection.endIndex { + addedIndexes.append(otherIndex) + otherIndex = otherCollection.index(after: otherIndex) + } + + return Diff(commonIndexes: DiffIndexSet(commonIndexes, startIndex: self.startIndex), + addedIndexes: DiffIndexSet(addedIndexes, startIndex: otherCollection.startIndex), + removedIndexes: DiffIndexSet(removedIndexes, startIndex: self.startIndex)) + } + + // MARK: Private functions + + private func prefix(_ otherCollection: Self, count: Int, suffix: Int) -> (Int, [Index]) { + var iterator = self.makeIterator() + var otherIterator = otherCollection.makeIterator() + + var prefix = self.startIndex + let endIndex = self.index(self.startIndex, offsetBy: count - suffix) + while let lhs = iterator.next(), let rhs = otherIterator.next(), lhs == rhs, prefix < endIndex { + prefix = self.index(after: prefix) + } + + let prefixLength = self.distance(from: self.startIndex, to: prefix) + return (prefixLength, Array(self.indices.prefix(prefixLength))) + } + + private func suffix(_ otherCollection: Self, count: Int) -> (Int, [Index]) { + var iterator = self.reversed().makeIterator() + var otherIterator = otherCollection.reversed().makeIterator() + + var offset = count + var suffix = self.index(self.startIndex, offsetBy: offset) + while let lhs = iterator.next(), let rhs = otherIterator.next(), lhs == rhs { + offset &-= 1 + suffix = self.index(self.startIndex, offsetBy: offset) + } + + let suffixLength = self.distance(from: suffix, to: self.endIndex) + return (suffixLength, Array(self.indices.suffix(suffixLength))) + } + + private func computeLCS(_ otherCollection: Self, prefixLength: Int, suffixLength: Int, count: Int) -> [Index] { + let rows = Int(count - prefixLength - suffixLength) + 1 + let columns = Int(otherCollection.count - prefixLength - suffixLength) + 1 + + guard rows > 1 && columns > 1 else { + return [] + } + + var lengths = Array(repeating: 0, count: rows * columns) + var index = self.index(self.startIndex, offsetBy: prefixLength) + for i in 0..<rows &- 1 { + var otherIndex = otherCollection.index(otherCollection.startIndex, offsetBy: prefixLength) + for j in 0..<columns &- 1 { + if self[index] == otherCollection[otherIndex] { + lengths[(i &+ 1) &* columns &+ j &+ 1] = lengths[i &* columns &+ j] &+ 1 + } else { + let lhs = lengths[(i &+ 1) &* columns &+ j] + let rhs = lengths[i &* columns &+ j &+ 1] + lengths[(i &+ 1) &* columns &+ j &+ 1] = Swift.max(lhs, rhs) + } + + otherIndex = otherCollection.index(after: otherIndex) + } + + index = self.index(after: index) + } + + var commonIndexes: [Index] = [] + + var indexOffset = count - suffixLength + index = self.index(self.startIndex, offsetBy: indexOffset) + var (i, j) = (rows &- 1, columns &- 1) + while i != 0 && j != 0 { + if lengths[i &* columns &+ j] == lengths[(i &- 1) &* columns &+ j] { + i = i &- 1 + indexOffset &-= 1 + index = self.index(self.startIndex, offsetBy: indexOffset) + } else if lengths[i &* columns &+ j] == lengths[i &* columns &+ j &- 1] { + j = j &- 1 + } else { + indexOffset &-= 1 + index = self.index(self.startIndex, offsetBy: indexOffset) + commonIndexes.append(index) + (i, j) = (i &- 1, j &- 1) + } + } + + return commonIndexes.reversed() + } + + fileprivate func longestCommonSubsequence(_ otherCollection: Self, selfCount count: Int) -> [Index] { + let (suffix, suffixIndexes) = self.suffix(otherCollection, count: count) + let (prefix, prefixIndexes) = self.prefix(otherCollection, count: count, suffix: suffix) + + return prefixIndexes + self.computeLCS(otherCollection, prefixLength: prefix, suffixLength: suffix, count: count) + suffixIndexes + } + +} + +// MARK: - +/** + An extension of `RangeReplaceableCollection`, which calculates the longest common subsequence between two collections. + */ +public extension RangeReplaceableCollection where Element: Equatable { + + /** + Returns the longest common subsequence between two collections. + + - parameter collection: The collection with which to compare the receiver. + - returns: The longest common subsequence between the receiver and the given collection. + */ + func longestCommonSubsequence(_ collection: Self) -> Self { + return Self(self.longestCommonSubsequence(collection, selfCount: self.count).map { self[$0] }) + } + +} diff --git a/mut/keuze/kies/TableView.swift b/mut/keuze/kies/TableView.swift new file mode 100644 index 0000000..cd7de9f --- /dev/null +++ b/mut/keuze/kies/TableView.swift @@ -0,0 +1,89 @@ +// +// KiesTableView.swift +// kies +// +// Created by Thomas Billiet on 08/04/2019. +// Copyright © 2019 Thomas Billiet. All rights reserved. +// + +import Foundation +import Cocoa + +class TableView: NSTableView, NSTableViewDelegate { + + let column = NSTableColumn(identifier: LIST_COL_ID) + + init(dataSource: DataSource) { + super.init(frame: .zero) + self.dataSource = dataSource + headerView = nil + allowsEmptySelection = false + allowsMultipleSelection = false + allowsTypeSelect = false + selectionHighlightStyle = .none + delegate = self + backgroundColor = .clear + + column.isEditable = false + column.width = layouts.listRect.width + addTableColumn(column) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func reloadData() { + super.reloadData() + scrollToBeginningOfDocument(self) + selectRow(0) + } + + func selectRow(_ row: Int) { + let indexSet = IndexSet(integer: row) + selectRowIndexes(indexSet, byExtendingSelection: false) + } + + func selectRowAbove() { + let row = selectedRow - 1 + if (row >= 0) { + selectRow(row) + scrollRowToVisible(row) + } + } + + func selectRowBelow() { + let row = selectedRow + 1 + if (row < numberOfRows) { + selectRow(row) + scrollRowToVisible(row) + } + } + + func tableView(_ tableView: NSTableView, willDisplayCell cell: Any, for tableColumn: NSTableColumn?, row: Int) { + let c = cell as! NSTextFieldCell + let value = c.stringValue + c.font = settings.font + c.usesSingleLineMode = true + if (row == selectedRow) { + c.backgroundColor = .alternateSelectedControlColor + c.textColor = .alternateSelectedControlTextColor + c.drawsBackground = true + } else { + c.drawsBackground = false + c.textColor = .textColor + } + let match = (dataSource as! DataSource).matches[value] + if (match != nil && !match!.isEmpty) { + let range = (value.lowercased() as NSString).range(of: match!) + let attribute = NSMutableAttributedString.init(string: value) + attribute.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue , range: range) + c.attributedStringValue = attribute + } + + } + + func tableViewSelectionDidChange(_ notification: Notification) { + } + +} diff --git a/mut/keuze/kies/Window.swift b/mut/keuze/kies/Window.swift new file mode 100644 index 0000000..078bdad --- /dev/null +++ b/mut/keuze/kies/Window.swift @@ -0,0 +1,51 @@ +// +// NSWindowExtension.swift +// kies +// +// Created by Thomas Billiet on 08/04/2019. +// Copyright © 2019 Thomas Billiet. All rights reserved. +// + +import Foundation +import Cocoa + +class Window: NSWindow { + override var canBecomeKey: Bool { + return true + } + + override var canBecomeMain: Bool { + return true + } + + init() { + super.init(contentRect: layouts.windowRect, styleMask: .borderless, backing: .buffered, defer: false) + isOpaque = true + canHide = false + isMovable = false + title = WINDOW_TITLE + level = NSWindow.Level.floating + hasShadow = true + backgroundColor = .clear + + let visualEffect = NSVisualEffectView() + visualEffect.blendingMode = .withinWindow + visualEffect.state = .active + visualEffect.material = .appearanceBased + visualEffect.frame = layouts.windowRect + contentView = visualEffect + } + + public func showWindow() { + positionWindowAtCenter() + makeMain() + makeKeyAndOrderFront(self) + } + + public func positionWindowAtCenter(){ + let xPos = NSWidth((self.screen?.frame)!)/2 - NSWidth(self.frame)/2 + let yPos = NSHeight((self.screen?.frame)!)/2 - NSHeight(self.frame)/2 + let frame = NSMakeRect(xPos, yPos, NSWidth(self.frame), NSHeight(self.frame)) + self.setFrame(frame, display: true) + } +} diff --git a/mut/keuze/kies/constants.swift b/mut/keuze/kies/constants.swift new file mode 100644 index 0000000..a142eac --- /dev/null +++ b/mut/keuze/kies/constants.swift @@ -0,0 +1,13 @@ +// +// Constants.swift +// kies +// +// Created by Thomas Billiet on 08/04/2019. +// Copyright © 2019 Thomas Billiet. All rights reserved. +// + +import Foundation +import Cocoa + +let WINDOW_TITLE = "Kies" +let LIST_COL_ID = NSUserInterfaceItemIdentifier(rawValue: "column"); diff --git a/mut/keuze/kies/main.swift b/mut/keuze/kies/main.swift new file mode 100644 index 0000000..a20922d --- /dev/null +++ b/mut/keuze/kies/main.swift @@ -0,0 +1,132 @@ +// +// main.swift +// kies +// +// Created by Thomas Billiet on 08/04/2019. +// Copyright © 2019 Thomas Billiet. All rights reserved. +// + +import Foundation +import Cocoa +import Darwin + +class AppDelegate: NSObject, NSApplicationDelegate { + + var window: Window! + var dataSource: DataSource! + var promptText: PromptText! + var divider: NSBox! + var inputField: InputField! + var tableView: TableView! + var scrollView: NSScrollView! + + func applicationDidBecomeActive(_ notification: Notification) { + + } + + func applicationDidResignActive(_ notification: Notification) { + cancel(); + } + + func receiveStdin() -> [String] { + var lines: [String] = [] + while let line = readLine() { + lines.append(line) + } + return lines + } + + func applicationDidFinishLaunching(_ notification: Notification) + { + if (settings.promptText == nil) { + fputs("Please provide a prompt text\n", stderr) + exit(1) + } + if (settings.font == nil) { + fputs("The provided font could not be loaded\n", stderr) + exit(1) + } + let items = receiveStdin() + if (items.count == 0) { + fputs("No data was received on stdin\n", stderr) + exit(1) + } + + window = Window() + dataSource = DataSource() + dataSource.updateItems(items) + + setupPromptText() + setupDivider() + setupInputField() + setupList() + + window.showWindow() + app.activate(ignoringOtherApps: true) + } + + func setupPromptText() { + promptText = PromptText(text: settings.promptText!) + window.contentView!.addSubview(promptText) + } + + func setupDivider() { + divider = NSBox(frame: layouts.dividerRect) + divider.boxType = .custom + divider.fillColor = .lightGray + divider.borderWidth = 0 + window.contentView!.addSubview(divider) + } + + func setupInputField() { + inputField = InputField(appDelegate: self); + window.contentView!.addSubview(inputField) + window.makeFirstResponder(inputField) + } + + func handleInputChange(input: String) { + dataSource.updateSort(query: input) + tableView.reloadData() + } + + func handleMoveUp() { + tableView.selectRowAbove() + } + + func handleMoveDown() { + tableView.selectRowBelow() + } + + func handleSelect() { + let value = dataSource.sortedItems[tableView.selectedRow] + fputs(value, stdout) + cancel() + } + + func setupList() { + scrollView = NSScrollView(frame: layouts.listRect) + tableView = TableView(dataSource: dataSource) + + scrollView.horizontalScrollElasticity = .none + scrollView.verticalScrollElasticity = .none + scrollView.hasVerticalScroller = true + scrollView.hasHorizontalScroller = false + scrollView.drawsBackground = false + scrollView.autoresizingMask = [NSView.AutoresizingMask.width, NSView.AutoresizingMask.height] + scrollView.documentView = tableView + scrollView.automaticallyAdjustsContentInsets = false + window.contentView!.addSubview(scrollView) + } + + func cancel() { + exit(0) + } +} + + +let app = NSApplication.shared +app.setActivationPolicy(.accessory) +let delegate = AppDelegate() +app.delegate = delegate + +_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) diff --git a/mut/keuze/screenshots/screenshot1.png b/mut/keuze/screenshots/screenshot1.png Binary files differnew file mode 100644 index 0000000..6b94279 --- /dev/null +++ b/mut/keuze/screenshots/screenshot1.png |
