1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-11-24 03:25:03 +03:00

Merge remote-tracking branch 'origin/develop' into update-neovim

This commit is contained in:
Tae Won Ha 2020-01-19 20:46:22 +01:00
commit 3662ce18a6
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
145 changed files with 11047 additions and 1235 deletions

View File

@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>SNAPSHOT-330</string>
<string>SNAPSHOT-331</string>
<key>CFBundleVersion</key>
<string>330</string>
<string>331</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>

View File

@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>SNAPSHOT-330</string>
<string>SNAPSHOT-331</string>
<key>CFBundleVersion</key>
<string>330</string>
<string>331</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>

View File

@ -38,9 +38,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>SNAPSHOT-330</string>
<string>SNAPSHOT-331</string>
<key>CFBundleVersion</key>
<string>330</string>
<string>331</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>

View File

@ -22,6 +22,9 @@
#include <nvim/fileio.h>
#include <nvim/api/private/helpers.h>
#include <api/vim.h.generated.h>
#include <nvim/ui.h>
#include <ui.h.generated.h>
#include <fileio.h.generated.h>
#include <nvim/aucmd.h>
#include "server_ui_bridge.h"
@ -219,7 +222,7 @@ void send_msg_packing(NvimServerMsgId msgid, pack_block body) {
msgpack_sbuffer_destroy(&sbuf);
}
static void start_nvim(void *_) {
static void start_nvim(void *arg __unused) {
backspace = cstr_as_string("<BS>");
setenv_vimruntime();
@ -370,7 +373,7 @@ static const char *cfstr2cstr(CFStringRef cfstr, bool *free_bytes) {
if (converted == 0 || out_len == 0) { return NULL; }
const char *result = malloc((size_t) (out_len + 1));
char *result = malloc((size_t) (out_len + 1));
converted = CFStringGetBytes(
cfstr,
whole_range,
@ -388,6 +391,7 @@ static const char *cfstr2cstr(CFStringRef cfstr, bool *free_bytes) {
}
*free_bytes = true;
result[out_len] = NULL;
return result;
}
@ -481,7 +485,7 @@ static void debug1(void **argv) {
});
}
static void do_autocmd_guienter(void **argv) {
static void do_autocmd_guienter(void **argv __unused) {
static bool recursive = false;
if (recursive) {

View File

@ -10,6 +10,7 @@
1929B00C084F8EA5EF0BE6E2 /* NvimView+Geometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD896D408673954F4AA2 /* NvimView+Geometry.swift */; };
1929B0533B55B2349DE2EFE2 /* foundation_shim.h in Headers */ = {isa = PBXBuildFile; fileRef = 1929B27A8FF9A75A09969777 /* foundation_shim.h */; settings = {ATTRIBUTES = (Public, ); }; };
1929B06F50B2585777FFBE48 /* NvimApiCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B002A03693B14B14BE34 /* NvimApiCommons.swift */; };
1929B09C1ADB384F37698FB8 /* NvimCursorModeShape.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B03EB461210D48D47510 /* NvimCursorModeShape.generated.swift */; };
1929B0B1A64AA449F666FCC9 /* 1.json in Resources */ = {isa = PBXBuildFile; fileRef = 1929B8619FD13BC2570CBFB2 /* 1.json */; };
1929B13ACA836714CD801F41 /* ConditionVariable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B4CC2D4AF391223461A2 /* ConditionVariable.swift */; };
1929B14D2EBC34BCFEC78ACB /* CellAttributesCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB19DD03ECD6ECC35F94 /* CellAttributesCollection.swift */; };
@ -19,6 +20,7 @@
1929B326D5117A670105C209 /* 2.json in Resources */ = {isa = PBXBuildFile; fileRef = 1929B0522C47787B50071806 /* 2.json */; };
1929B36C51BCDFCCEE974EA2 /* SwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9C55A79D97272894F5D /* SwiftCommons.swift */; };
1929B3B70C96A78FD63DE737 /* NvimView+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDC8F32F4A0D2299B5C5 /* NvimView+Debug.swift */; };
1929B3D4281D2E30A9603368 /* NvimCursorModeShape.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B03EB461210D48D47510 /* NvimCursorModeShape.generated.swift */; };
1929B40A751BDA2882D4FC94 /* NvimView+Objects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B22A0CAD417EC3790F02 /* NvimView+Objects.swift */; };
1929B40C9C30B46C0E0B9DE2 /* CellAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE45756C88F8B43804D2 /* CellAttributes.swift */; };
1929B434C0299827CCE6D1CC /* Defs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BF14AE831C6832659B66 /* Defs.swift */; };
@ -32,7 +34,6 @@
1929B74691D92B9F369787E5 /* ColorUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDE2C6003A6EDC02129C /* ColorUtils.swift */; };
1929B7D2EB80FEA7BFBC3D2C /* Typesetter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B47330DAD129520A2273 /* Typesetter.swift */; };
1929B83EAD32DC419FEC68DB /* CocoaCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0C89838D8402BB80BFC /* CocoaCommons.swift */; };
1929B90E2CFEAADE0CEE1562 /* CursorModeShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA4C89E9FE90065C32F6 /* CursorModeShape.swift */; };
1929B922396A4EE7F070299A /* PerfTester.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B114CC85D012D7477D58 /* PerfTester.swift */; };
1929B953E76914DA984697DC /* FontUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B96A876229DA394F906E /* FontUtils.swift */; };
1929B9A949EE85C27FF66367 /* UGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9D83D7E150F518D49FE /* UGrid.swift */; };
@ -44,7 +45,6 @@
1929BB552C9D99E9ED938759 /* CellAttributesCollectionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0B60CCAA00B08ACAB15 /* CellAttributesCollectionTest.swift */; };
1929BC8495028D66F0A7D618 /* AttributesRunDrawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB7E3430BD3FD88A7698 /* AttributesRunDrawer.swift */; };
1929BCA615324C58582BFC3C /* ProcessUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD167BE7C6BB788DAE2A /* ProcessUtils.swift */; };
1929BCF2B3C24F0E9A96FE25 /* CursorModeShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA4C89E9FE90065C32F6 /* CursorModeShape.swift */; };
1929BDB2462E19B852EA1B47 /* CoreCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BAB9FFE8345228B559EC /* CoreCommons.swift */; };
1929BDC146B699BF49116CAB /* Defs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BF14AE831C6832659B66 /* Defs.swift */; };
1929BDD254F59FC0F5B800E7 /* Geometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B73455764E42DACF6BB8 /* Geometry.swift */; };
@ -235,6 +235,7 @@
/* Begin PBXFileReference section */
1929B002A03693B14B14BE34 /* NvimApiCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NvimApiCommons.swift; sourceTree = "<group>"; };
1929B03EB461210D48D47510 /* NvimCursorModeShape.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NvimCursorModeShape.generated.swift; sourceTree = "<group>"; };
1929B0522C47787B50071806 /* 2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = 2.json; sourceTree = "<group>"; };
1929B06A73BE6DAA2679AAA2 /* Runs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Runs.swift; sourceTree = "<group>"; };
1929B086022A7A2C99A65A21 /* 0.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = 0.json; sourceTree = "<group>"; };
@ -258,7 +259,6 @@
1929B9C55A79D97272894F5D /* SwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftCommons.swift; sourceTree = "<group>"; };
1929B9D7F040B8B9E2F038DF /* FontTrait.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FontTrait.swift; sourceTree = "<group>"; };
1929B9D83D7E150F518D49FE /* UGrid.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UGrid.swift; sourceTree = "<group>"; };
1929BA4C89E9FE90065C32F6 /* CursorModeShape.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CursorModeShape.swift; sourceTree = "<group>"; };
1929BAB0B8BA4E6CDF5C56F3 /* NvimView+Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NvimView+Types.swift"; sourceTree = "<group>"; };
1929BAB9FFE8345228B559EC /* CoreCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreCommons.swift; sourceTree = "<group>"; };
1929BAF033A398BFBC2A7890 /* MyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyView.swift; sourceTree = "<group>"; };
@ -524,11 +524,11 @@
1929B2BA05AC3E1A11D6EBFC /* Commons */,
1929BDC8F32F4A0D2299B5C5 /* NvimView+Debug.swift */,
1929BD896D408673954F4AA2 /* NvimView+Geometry.swift */,
1929BA4C89E9FE90065C32F6 /* CursorModeShape.swift */,
1929BF14AE831C6832659B66 /* Defs.swift */,
1929B27A8FF9A75A09969777 /* foundation_shim.h */,
1929BAB0B8BA4E6CDF5C56F3 /* NvimView+Types.swift */,
1929B4CC2D4AF391223461A2 /* ConditionVariable.swift */,
1929B03EB461210D48D47510 /* NvimCursorModeShape.generated.swift */,
);
path = NvimView;
sourceTree = "<group>";
@ -879,11 +879,11 @@
1929BF6E40C70A4157A5C755 /* UGridTest.swift in Sources */,
1929BB552C9D99E9ED938759 /* CellAttributesCollectionTest.swift in Sources */,
4B02268C224ACFE30052362B /* ReadersWriterLock.swift in Sources */,
1929B90E2CFEAADE0CEE1562 /* CursorModeShape.swift in Sources */,
4BB1EFB3224B71ED00A5CD5A /* RxNeovimApi.generated.swift in Sources */,
1929BDC146B699BF49116CAB /* Defs.swift in Sources */,
1929B2E9F089A9E2800B67F2 /* NimbleCommons.swift in Sources */,
1929BB125782E25A9CF7F56C /* ConditionVariable.swift in Sources */,
1929B09C1ADB384F37698FB8 /* NvimCursorModeShape.generated.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -929,11 +929,11 @@
4BB1EFB4224B71ED00A5CD5A /* RxSwiftCommons.swift in Sources */,
1929B00C084F8EA5EF0BE6E2 /* NvimView+Geometry.swift in Sources */,
1929B06F50B2585777FFBE48 /* NvimApiCommons.swift in Sources */,
1929BCF2B3C24F0E9A96FE25 /* CursorModeShape.swift in Sources */,
1929B5C5DB438B66EC131EDE /* Defs.swift in Sources */,
1929B4C729F3713A6BBEAEC9 /* OSLogCommons.swift in Sources */,
1929BA25DA32AE80C527BB2A /* NvimView+Types.swift in Sources */,
1929B13ACA836714CD801F41 /* ConditionVariable.swift in Sources */,
1929B3D4281D2E30A9603368 /* NvimCursorModeShape.generated.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1146,7 +1146,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 330;
CURRENT_PROJECT_VERSION = 331;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -1208,7 +1208,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 330;
CURRENT_PROJECT_VERSION = 331;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -1238,7 +1238,7 @@
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 330;
DYLIB_CURRENT_VERSION = 331;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
FRAMEWORK_VERSION = A;
@ -1260,7 +1260,7 @@
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 330;
DYLIB_CURRENT_VERSION = 331;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
FRAMEWORK_VERSION = A;

View File

@ -1,30 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
// Keep in sync with ModeShape enum in cursor_shape.h.
public enum CursorModeShape: UInt {
case normal = 0
case visual
case insert
case replace
case cmdline
case cmdlineInsert
case cmdlineReplace
case operatorPending
case visualExclusive
case onCmdline
case onStatusLine
case draggingStatusLine
case onVerticalSepLine
case draggingVerticalSepLine
case more
case moreLastLine
case showingMatchingParen
case termFocus
case count
}

View File

@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>SNAPSHOT-330</string>
<string>SNAPSHOT-331</string>
<key>CFBundleVersion</key>
<string>330</string>
<string>331</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2017 Tae Won Ha. All rights reserved.</string>
<key>NSPrincipalClass</key>

View File

@ -115,3 +115,4 @@ enum NvimAutoCommandEvent: Int {
case winleave = 109
case winnew = 110
}

View File

@ -0,0 +1,27 @@
// Auto generated for nvim v0.4.3
// See bin/generate_cursor_shape.py
public enum CursorModeShape: UInt {
case normal = 0
case visual = 1
case insert = 2
case replace = 3
case cmdlineNormal = 4
case cmdlineInsert = 5
case cmdlineReplace = 6
case operatorPending = 7
case visualExclusive = 8
case onCmdline = 9
case onStatusLine = 10
case draggingStatusLine = 11
case onVerticalSepLine = 12
case draggingVerticalSepLine = 13
case more = 14
case moreLastLine = 15
case showingMatchingParen = 16
case termFocus = 17
case count = 18
}

View File

@ -9,6 +9,10 @@ import MessagePack
extension NvimView {
public func isBlocked() -> Single<Bool> {
return self.api.getMode().map { dict in dict["blocking"]?.boolValue ?? false }
}
public func waitTillNvimExits() {
self.nvimExitedCondition.wait(for: 5)
}

View File

@ -68,7 +68,7 @@ extension NvimView {
case .visual: return "Visual"
case .insert: return "Insert"
case .replace: return "Replace"
case .cmdline: return "Cmdline"
case .cmdlineNormal: return "Cmdline"
case .cmdlineInsert: return "CmdlineInsert"
case .cmdlineReplace: return "CmdlineReplace"
case .operatorPending: return "OperatorPending"

View File

@ -121,7 +121,7 @@ extension NvimView {
return
}
if self.mode == .cmdline || self.mode == .cmdlineInsert || self.mode == .cmdlineReplace
if self.mode == .cmdlineNormal || self.mode == .cmdlineInsert || self.mode == .cmdlineReplace
|| self.mode == .replace
|| self.mode == .termFocus {
self.api

View File

@ -87,10 +87,10 @@ extension NvimView {
rowStart = r ? min(rowStart, s) : rowStart
case .goto:
guard let row = innerArray[0].unsignedIntegerValue,
let col = innerArray[1].unsignedIntegerValue,
let textPositionRow = innerArray[2].unsignedIntegerValue,
let textPositionCol = innerArray[3].unsignedIntegerValue else { return }
guard let row = innerArray[0].uint64Value,
let col = innerArray[1].uint64Value,
let textPositionRow = innerArray[2].uint64Value,
let textPositionCol = innerArray[3].uint64Value else { return }
self.doGoto(
position: Position(row: Int(row), column: Int(col)),
@ -489,7 +489,7 @@ extension NvimView {
}
guard let id = array[0].intValue,
let rawTrait = array[1].unsignedIntegerValue,
let rawTrait = array[1].uint64Value,
let fg = array[2].intValue,
let bg = array[3].intValue,
let sp = array[4].intValue,

View File

@ -15,8 +15,8 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>SNAPSHOT-330</string>
<string>SNAPSHOT-331</string>
<key>CFBundleVersion</key>
<string>330</string>
<string>331</string>
</dict>
</plist>

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9cfd2a5d30525406eb4326171a7d43641105bea0d11eebea2bd161186c459929
oid sha256:d26911f127c071ad3614ffe5506cb48eb018ebf4f203e528e5ca3be5648eebad
size 71680

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:14bcee7757d7dfa751eb33c554a1c3b6230ae9fe4e9dd5a22d5a238aaa1036bd
size 100832
oid sha256:da69917872f71d621ac0083cb03b7bd585ef7d8c7ac8e8c709569e3eaa049aae
size 100824

View File

@ -5,7 +5,7 @@ VimR — Neovim Refined
[Download](https://github.com/qvacua/vimr/releases) • [Documentation](https://github.com/qvacua/vimr/wiki) • <http://vimr.org>
[![Bountysource](https://www.bountysource.com/badge/team?team_id=933&style=raised)](https://www.bountysource.com/teams/vimr?utm_source=VimR%20%E2%80%94%20Vim%20Refined&utm_medium=shield&utm_campaign=raised) [![Chat at https://gitter.im/vimr/vimr](https://badges.gitter.im/vimr/vimr.svg)](https://gitter.im/vimr/vimr?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Stories in Ready](https://badge.waffle.io/qvacua/vimr.svg?label=ready&title=Ready)](http://waffle.io/qvacua/vimr)
[![Bountysource](https://www.bountysource.com/badge/team?team_id=933&style=raised)](https://www.bountysource.com/teams/vimr?utm_source=VimR%20%E2%80%94%20Vim%20Refined&utm_medium=shield&utm_campaign=raised) [![Chat at https://gitter.im/vimr/vimr](https://badges.gitter.im/vimr/vimr.svg)](https://gitter.im/vimr/vimr?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Screenshot 1](https://raw.githubusercontent.com/qvacua/vimr/develop/resources/screenshot1.png)
![Screenshot 0](https://raw.githubusercontent.com/qvacua/vimr/develop/resources/screenshot0.png)
@ -48,7 +48,7 @@ Pre-built binaries can be found under [Releases](https://github.com/qvacua/vimr/
* (Simple) File browser
* Flexible workspace model a la JetBrain's IDEs
We will gradually create feature [issues](https://github.com/qvacua/vimr/issues) with more details. For the current status see the [project board](https://waffle.io/qvacua/vimr).
We will gradually create feature [issues](https://github.com/qvacua/vimr/issues) with more details.
## How to Build

View File

@ -259,7 +259,7 @@ public final class RxMsgpackRpc {
return
}
guard let rawType = array[0].unsignedIntegerValue,
guard let rawType = array[0].uint64Value,
let type = MessageType(rawValue: rawType)
else {
self.streamSubject.onNext(.error(
@ -280,7 +280,7 @@ public final class RxMsgpackRpc {
return
}
guard let msgid64 = array[1].unsignedIntegerValue else {
guard let msgid64 = array[1].uint64Value else {
self.streamSubject.onNext(.error(
value: unpacked,
msg: "Could not get the msgid"

View File

@ -25,7 +25,7 @@ extension RxNeovimApi {
return
}
guard let rawValue = array?[0].unsignedIntegerValue, let message = array?[1].stringValue else {
guard let rawValue = array?[0].uint64Value, let message = array?[1].stringValue else {
self = .unknown
return
}

View File

@ -111,7 +111,7 @@ extension RxNeovimApi {
return
}
guard let rawValue = array?[0].unsignedIntegerValue, let message = array?[1].stringValue else {
guard let rawValue = array?[0].uint64Value, let message = array?[1].stringValue else {
self = .unknown
return
}

View File

@ -19,14 +19,12 @@
1929B29B95AD176D57942E08 /* UiRootReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B457B9D0FA4D21F3751E /* UiRootReducer.swift */; };
1929B2D56C4652E251C23AD4 /* DefaultShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B93256AF7F9137223E36 /* DefaultShortcuts.swift */; };
1929B3217A7A3D79E28C80DB /* PrefWindowReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B49E6924847AD085C8C9 /* PrefWindowReducer.swift */; };
1929B333855A5406C400DA92 /* OpenQuicklyFilterOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEDE7F92BC7B49E802AF /* OpenQuicklyFilterOperation.swift */; };
1929B3557317755A43513B17 /* OpenQuicklyWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B71A92C24FEFE79A851E /* OpenQuicklyWindow.swift */; };
1929B370A275F8C70AD5AA08 /* UrlCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B11D672134E52A256A7F /* UrlCommonsTest.swift */; };
1929B376DB09AB5FDBF42BA1 /* MainWindow+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B41F704A4D67621197ED /* MainWindow+Types.swift */; };
1929B3A6C332FFAAEC7FD219 /* MainWindow+CustomTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B71B4BB6550F5BC6D4CF /* MainWindow+CustomTitle.swift */; };
1929B3AC66EFE35D68C020E3 /* PreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFB0F294F3714D5E095F /* PreviewToolReducer.swift */; };
1929B3F5743967125F357C9F /* Matcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEEB33113B0E33C3830F /* Matcher.swift */; };
1929B462CD4935AFF6D69457 /* FileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7CB4863F80230C32D3C /* FileItem.swift */; };
1929B443B7AB2176A7818CA1 /* fuzzy_match.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1B01340283D6AAD6B06 /* fuzzy_match.cc */; };
1929B4B00D7BB191A9A6532D /* HtmlPreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE5AEA3D0980860EED50 /* HtmlPreviewToolReducer.swift */; };
1929B4B70926DE113E6BF990 /* PreviewReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE37AA2843779CAFA76F /* PreviewReducer.swift */; };
1929B4E54E2F13A7F5F2B682 /* BufferListReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B67A10E6BB2986B2416E /* BufferListReducer.swift */; };
@ -35,8 +33,8 @@
1929B4FEE6EB56EF3F56B805 /* Context.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B34FC23D805A8B29E8F7 /* Context.swift */; };
1929B50D933A369A86A165DE /* AdvencedPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBE0A534F2F6009D31BE /* AdvencedPref.swift */; };
1929B5257DB27F03C6663482 /* MainWindow+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B067B3247675BCD09218 /* MainWindow+Actions.swift */; };
1929B53876E6952D378C2B30 /* ScoredFileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */; };
1929B542A071BD03C846F6EF /* PrefUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8241CDE58F7AAF89AE4 /* PrefUtils.swift */; };
1929B543D5C82485F053CF17 /* FuzzySearch.xcdatamodel in Sources */ = {isa = PBXBuildFile; fileRef = 1929B656C04BA6F950BFA2F5 /* FuzzySearch.xcdatamodel */; };
1929B5543B1E31A26096E656 /* FileMonitorReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B04EC69F616EEFAF5F96 /* FileMonitorReducer.swift */; };
1929B560C6CE264FD1E1F5A3 /* com.qvacua.VimR.vim in Resources */ = {isa = PBXBuildFile; fileRef = 1929BC6D45B7E14D4D75D4E6 /* com.qvacua.VimR.vim */; };
1929B59FA5C286E010F70BEE /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFC0A5A9C6DB09BE1368 /* Types.swift */; };
@ -44,7 +42,6 @@
1929B5A2EE366F79ED32744C /* KeysPrefReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B88B5FA08E897A3C2168 /* KeysPrefReducer.swift */; };
1929B5C1BABBC0D09D97C3EF /* PreviewMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B617C229B19DB3E987B8 /* PreviewMiddleware.swift */; };
1929B5F016431A76292D1E84 /* FileMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B365A6434354B568B04F /* FileMonitor.swift */; };
1929B6388EAF16C190B82955 /* FileItemIgnorePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */; };
1929B6460862447A31B5B082 /* ImageAndTextTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDC3F82CB4CB4FE56D1B /* ImageAndTextTableCell.swift */; };
1929B66F795867B8C07FAAD4 /* DictionaryCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9355C892BEBA7496C71 /* DictionaryCommonsTest.swift */; };
1929B67DA3EB21A631EF1DBB /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA8AC40B901B20F20B71 /* FileUtils.swift */; };
@ -58,14 +55,13 @@
1929B8F498D1E7C53F572CE2 /* KeysPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B14A5949FB64C4B2646F /* KeysPref.swift */; };
1929B8FB248D71BF88A35761 /* PreviewTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B6C6C7792B05164B0216 /* PreviewTool.swift */; };
1929B9318D32146D58BB38EC /* AppKitCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70931D60E04200E12030 /* AppKitCommons.swift */; };
1929B94083273D4B321AD848 /* FileItemUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B56C8ED31834BA9D8543 /* FileItemUtils.swift */; };
1929B98F94536E3912AD9F3B /* ArrayCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BAF13FAD5DA8D3762367 /* ArrayCommonsTest.swift */; };
1929B990A143763A56CFCED0 /* PrefMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B364460D86F17E80943C /* PrefMiddleware.swift */; };
1929BA269EBD68251410A08E /* ShortcutsTableSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B07F0085B7AE10413346 /* ShortcutsTableSubviews.swift */; };
1929BA715337FE26155B2071 /* BufferList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA43449BA41666CD55ED /* BufferList.swift */; };
1929BA76A1D97D8226F7CFB1 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B6AD3396160AA2C46919 /* Debouncer.swift */; };
1929BAAD7336FDFF1F78E749 /* ScorerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BF69B01107F358CF7EAD /* ScorerTest.swift */; };
1929BAE4900D72A7877741B1 /* PrefWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE168F31344B69E61B62 /* PrefWindow.swift */; };
1929BAEE911EC7620EE51911 /* fuzzy_match.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1B01340283D6AAD6B06 /* fuzzy_match.cc */; };
1929BAFF1E011321D3186EE6 /* UiRoot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD4149D5A25C82064DD8 /* UiRoot.swift */; };
1929BB4A9B2FA42A64CCCC76 /* MainWindowReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD83A13BF133741766CC /* MainWindowReducer.swift */; };
1929BB67CAAD4F6CBD38DF0A /* RxRedux.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B66A5E2D00EA143AFD86 /* RxRedux.swift */; };
@ -76,7 +72,6 @@
1929BCF7F7B9CC5499A3F506 /* AdvancedPrefReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7039C5689CE45F53888 /* AdvancedPrefReducer.swift */; };
1929BD2F41D93ADFF43C1C98 /* NetUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1929B02440BC99C42F9EBD45 /* NetUtils.m */; };
1929BD3878A3A47B8D685CD2 /* AppDelegateReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7A68B7109CEFAF105E8 /* AppDelegateReducer.swift */; };
1929BD3F9E609BFADB27584B /* Scorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9D510177918080BE39B /* Scorer.swift */; };
1929BDFDBDA7180D02ACB37E /* RxSwiftCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B6C215ACCBE12672A8D7 /* RxSwiftCommonsTest.swift */; };
1929BE0DAEE9664C5BCFA211 /* States.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB6608B4F0E037CA0F4C /* States.swift */; };
1929BE0F64A6CE5BCE2A5092 /* MainWindow+Delegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B714EB137AE448CE8ABD /* MainWindow+Delegates.swift */; };
@ -84,11 +79,10 @@
1929BE601267D52FA2E0D6D2 /* Defs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7F7A4B3FD52263D211D /* Defs.swift */; };
1929BEAE0592096BC1191B67 /* PrefPane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B07A4A9209C88380E015 /* PrefPane.swift */; };
1929BEDE1BE950EDA9497363 /* GeneralPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB55946DAEBF55D24048 /* GeneralPref.swift */; };
1929BEFEABA0448306CDB6D4 /* FileItemIgnorePatternTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */; };
1929BF03FD6465F289AA80B2 /* ToolsPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB2AD21A10A0ECA66A5E /* ToolsPref.swift */; };
1929BF3253594E5B1908C6CE /* RpcAppearanceEpic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B230EE8F1428980988F0 /* RpcAppearanceEpic.swift */; };
1929BF4FF30D9A9DE82C3052 /* FileUtilsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8042AC566CDF6C998A3 /* FileUtilsTest.swift */; };
1929BFC70581084B5CE04A5B /* MatcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFE179BCA3C75A13D71B /* MatcherTests.swift */; };
1929BF5D0EFCC56A733BB4B7 /* FuzzySearch.xcdatamodel in Sources */ = {isa = PBXBuildFile; fileRef = 1929B656C04BA6F950BFA2F5 /* FuzzySearch.xcdatamodel */; };
1929BFDE22D155F7C4B19E96 /* HtmlPreviewTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B85023B042C485409CE1 /* HtmlPreviewTool.swift */; };
4B004BCF21063B600043A396 /* DictionaryDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B004BCB21063B600043A396 /* DictionaryDecoder.swift */; };
4B004BD021063B600043A396 /* DictionaryDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B004BCB21063B600043A396 /* DictionaryDecoder.swift */; };
@ -111,13 +105,8 @@
4B2636B1223A487B00021586 /* SwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70951D6100E300E12030 /* SwiftCommons.swift */; };
4B2636B2223A487B00021586 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEBA5081CFF374B00673FDF /* AppDelegate.swift */; };
4B2636B3223A487B00021586 /* WorkspaceTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423991D8EFE3000FC78C8 /* WorkspaceTool.swift */; };
4B2636B4223A487B00021586 /* FileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7CB4863F80230C32D3C /* FileItem.swift */; };
4B2636B5223A487B00021586 /* FileItemIgnorePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */; };
4B2636B6223A487B00021586 /* DictionaryErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B004BCE21063B600043A396 /* DictionaryErrors.swift */; };
4B2636B7223A487B00021586 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA8AC40B901B20F20B71 /* FileUtils.swift */; };
4B2636B8223A487B00021586 /* Matcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEEB33113B0E33C3830F /* Matcher.swift */; };
4B2636B9223A487B00021586 /* ScoredFileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */; };
4B2636BA223A487B00021586 /* Scorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9D510177918080BE39B /* Scorer.swift */; };
4B2636BB223A487B00021586 /* ProxyWorkspaceBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB409ED1DDA77E9005F39A2 /* ProxyWorkspaceBar.swift */; };
4B2636BC223A487B00021586 /* FoundationCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */; };
4B2636BD223A487B00021586 /* NetUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1929B02440BC99C42F9EBD45 /* NetUtils.m */; };
@ -151,12 +140,10 @@
4B2636D9223A487B00021586 /* AdvencedPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBE0A534F2F6009D31BE /* AdvencedPref.swift */; };
4B2636DA223A487B00021586 /* AppearancePrefReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BED01F5D94BFCA4CF80F /* AppearancePrefReducer.swift */; };
4B2636DB223A487B00021586 /* OpenQuicklyWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B71A92C24FEFE79A851E /* OpenQuicklyWindow.swift */; };
4B2636DC223A487B00021586 /* OpenQuicklyFilterOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEDE7F92BC7B49E802AF /* OpenQuicklyFilterOperation.swift */; };
4B2636DD223A487B00021586 /* OpenQuicklyFileViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1558455B3A74D93EF2A /* OpenQuicklyFileViewRow.swift */; };
4B2636DE223A487B00021586 /* PrefMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B364460D86F17E80943C /* PrefMiddleware.swift */; };
4B2636DF223A487B00021586 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B6AD3396160AA2C46919 /* Debouncer.swift */; };
4B2636E0223A487B00021586 /* PreviewUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8EF9A9F5ACC175452BD /* PreviewUtils.swift */; };
4B2636E1223A487B00021586 /* FileItemUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B56C8ED31834BA9D8543 /* FileItemUtils.swift */; };
4B2636E2223A487B00021586 /* HtmlPreviewTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B85023B042C485409CE1 /* HtmlPreviewTool.swift */; };
4B2636E3223A487B00021586 /* HtmlPreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE5AEA3D0980860EED50 /* HtmlPreviewToolReducer.swift */; };
4B2636E4223A487B00021586 /* AdvancedPrefReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7039C5689CE45F53888 /* AdvancedPrefReducer.swift */; };
@ -373,10 +360,7 @@
4B94341420B95EC7005807BA /* MacVim-sch.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4B9433D920B95EC6005807BA /* MacVim-sch.icns */; };
4B94341520B95EC7005807BA /* MacVim-ps.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4B9433DA20B95EC6005807BA /* MacVim-ps.icns */; };
4B94341620B95EC7005807BA /* MacVim-css.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4B9433DB20B95EC6005807BA /* MacVim-css.icns */; };
4B96FB3B1EBBC56F00E4E164 /* FileItemIgnorePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */; };
4B96FB3C1EBBC56F00E4E164 /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA8AC40B901B20F20B71 /* FileUtils.swift */; };
4B96FB3D1EBBC56F00E4E164 /* Matcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEEB33113B0E33C3830F /* Matcher.swift */; };
4B96FB3E1EBBC56F00E4E164 /* Scorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9D510177918080BE39B /* Scorer.swift */; };
4B96FB3F1EBBC56F00E4E164 /* PrefUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8241CDE58F7AAF89AE4 /* PrefUtils.swift */; };
4B96FB401EBBC56F00E4E164 /* FoundationCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */; };
4B96FB421EBBC56F00E4E164 /* SwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70951D6100E300E12030 /* SwiftCommons.swift */; };
@ -429,6 +413,24 @@
4BF18C571FD2E52300DF95D1 /* NvimView.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4BC1642B1FD2DEE1001903BE /* NvimView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4BF18C581FD2E53400DF95D1 /* CocoaMarkdown.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BF18C331FD2E2AA00DF95D1 /* CocoaMarkdown.framework */; };
4BF18C591FD2E53B00DF95D1 /* CocoaMarkdown.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4BF18C331FD2E2AA00DF95D1 /* CocoaMarkdown.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4BF70EC423D1B3F9009E51E9 /* FuzzyMatcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EBF23D1B3F9009E51E9 /* FuzzyMatcher.mm */; };
4BF70EC523D1B3F9009E51E9 /* FuzzyMatcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EBF23D1B3F9009E51E9 /* FuzzyMatcher.mm */; };
4BF70EC823D1B3F9009E51E9 /* FuzzyMatcherPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EC323D1B3F9009E51E9 /* FuzzyMatcherPool.swift */; };
4BF70EC923D1B3F9009E51E9 /* FuzzyMatcherPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EC323D1B3F9009E51E9 /* FuzzyMatcherPool.swift */; };
4BF70ED223D1B4AF009E51E9 /* FoundationCommons.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70ED123D1B4AF009E51E9 /* FoundationCommons.m */; };
4BF70ED323D1B4AF009E51E9 /* FoundationCommons.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70ED123D1B4AF009E51E9 /* FoundationCommons.m */; };
4BF70ED623D1B54F009E51E9 /* ScoredUrl.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70ED523D1B54F009E51E9 /* ScoredUrl.m */; };
4BF70ED723D1B54F009E51E9 /* ScoredUrl.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70ED523D1B54F009E51E9 /* ScoredUrl.m */; };
4BF70EE123D1B5B3009E51E9 /* FileScanBaton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EDF23D1B5B3009E51E9 /* FileScanBaton.m */; };
4BF70EE223D1B5B3009E51E9 /* FileScanBaton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EDF23D1B5B3009E51E9 /* FileScanBaton.m */; };
4BF70EE523D1B5EC009E51E9 /* FuzzySearchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EE323D1B5EC009E51E9 /* FuzzySearchService.swift */; };
4BF70EE623D1B5EC009E51E9 /* FuzzySearchService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EE323D1B5EC009E51E9 /* FuzzySearchService.swift */; };
4BF70EE723D1B5EC009E51E9 /* FuzzySearchFileMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EE423D1B5EC009E51E9 /* FuzzySearchFileMonitor.swift */; };
4BF70EE823D1B5EC009E51E9 /* FuzzySearchFileMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EE423D1B5EC009E51E9 /* FuzzySearchFileMonitor.swift */; };
4BF70EEA23D1B5FF009E51E9 /* CoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EE923D1B5FF009E51E9 /* CoreDataStack.swift */; };
4BF70EEB23D1B5FF009E51E9 /* CoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EE923D1B5FF009E51E9 /* CoreDataStack.swift */; };
4BF70EED23D1B618009E51E9 /* ConditionVariable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EEC23D1B618009E51E9 /* ConditionVariable.swift */; };
4BF70EEE23D1B619009E51E9 /* ConditionVariable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF70EEC23D1B618009E51E9 /* ConditionVariable.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -510,13 +512,22 @@
1929B067B3247675BCD09218 /* MainWindow+Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MainWindow+Actions.swift"; sourceTree = "<group>"; };
1929B07A4A9209C88380E015 /* PrefPane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefPane.swift; sourceTree = "<group>"; };
1929B07F0085B7AE10413346 /* ShortcutsTableSubviews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsTableSubviews.swift; sourceTree = "<group>"; };
1929B0A888EA54E5C8FD04C7 /* search.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = search.h; path = "../../third-party/libag/include/search.h"; sourceTree = "<group>"; };
1929B0E63986F95E2F8DFF21 /* FileItem+CoreDataClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FileItem+CoreDataClass.h"; sourceTree = "<group>"; };
1929B0E9B2F018D3E31D4B0B /* ShortcutsPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsPref.swift; sourceTree = "<group>"; };
1929B0EA67C53B49B98182CA /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = log.h; path = "../../third-party/libag/include/log.h"; sourceTree = "<group>"; };
1929B0EB3F49C42A57D083AF /* GeneralPrefReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralPrefReducer.swift; sourceTree = "<group>"; };
1929B0FBFB766042CF06E463 /* AppearancePref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppearancePref.swift; sourceTree = "<group>"; };
1929B11D672134E52A256A7F /* UrlCommonsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UrlCommonsTest.swift; sourceTree = "<group>"; };
1929B12CE56A9B36980288A4 /* OpenQuicklyReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyReducer.swift; sourceTree = "<group>"; };
1929B13E47E7D20EA99EDF92 /* print.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = print.h; path = "../../third-party/libag/include/print.h"; sourceTree = "<group>"; };
1929B13F14CABB7BDCD16B5D /* options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = options.h; path = "../../third-party/libag/include/options.h"; sourceTree = "<group>"; };
1929B14A5949FB64C4B2646F /* KeysPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeysPref.swift; sourceTree = "<group>"; };
1929B14F9B30D4A3FA1871A9 /* uthash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uthash.h; path = "../../third-party/libag/include/uthash.h"; sourceTree = "<group>"; };
1929B1534B8857C519D7C0FB /* FileItem+CoreDataProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FileItem+CoreDataProperties.h"; sourceTree = "<group>"; };
1929B1558455B3A74D93EF2A /* OpenQuicklyFileViewRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyFileViewRow.swift; sourceTree = "<group>"; };
1929B17B1BC7CA08DC76495C /* FileItem+CoreDataProperties.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "FileItem+CoreDataProperties.m"; sourceTree = "<group>"; };
1929B1B01340283D6AAD6B06 /* fuzzy_match.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fuzzy_match.cc; path = FuzzyMatcher/fuzzy_match.cc; sourceTree = "<group>"; };
1929B1DC584C89C477E83FA2 /* HttpServerMiddleware.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpServerMiddleware.swift; sourceTree = "<group>"; };
1929B230EE8F1428980988F0 /* RpcAppearanceEpic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RpcAppearanceEpic.swift; sourceTree = "<group>"; };
1929B34FC23D805A8B29E8F7 /* Context.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Context.swift; sourceTree = "<group>"; };
@ -525,13 +536,13 @@
1929B41F704A4D67621197ED /* MainWindow+Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MainWindow+Types.swift"; sourceTree = "<group>"; };
1929B457B9D0FA4D21F3751E /* UiRootReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UiRootReducer.swift; sourceTree = "<group>"; };
1929B49E6924847AD085C8C9 /* PrefWindowReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefWindowReducer.swift; sourceTree = "<group>"; };
1929B56C8ED31834BA9D8543 /* FileItemUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemUtils.swift; sourceTree = "<group>"; };
1929B5D45C9792BBE76B8AFF /* StringCommonsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringCommonsTest.swift; sourceTree = "<group>"; };
1929B617C229B19DB3E987B8 /* PreviewMiddleware.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewMiddleware.swift; sourceTree = "<group>"; };
1929B656C04BA6F950BFA2F5 /* FuzzySearch.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = FuzzySearch.xcdatamodel; sourceTree = "<group>"; };
1929B66A5E2D00EA143AFD86 /* RxRedux.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxRedux.swift; sourceTree = "<group>"; };
1929B672CE187B4D3EA1D3EE /* fuzzy_match.hh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = fuzzy_match.hh; path = FuzzyMatcher/fuzzy_match.hh; sourceTree = "<group>"; };
1929B67A10E6BB2986B2416E /* BufferListReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BufferListReducer.swift; sourceTree = "<group>"; };
1929B694508FB5FDE607513A /* ToolsPrefReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolsPrefReducer.swift; sourceTree = "<group>"; };
1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemIgnorePattern.swift; sourceTree = "<group>"; };
1929B6AD3396160AA2C46919 /* Debouncer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = "<group>"; };
1929B6C215ACCBE12672A8D7 /* RxSwiftCommonsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxSwiftCommonsTest.swift; sourceTree = "<group>"; };
1929B6C6C7792B05164B0216 /* PreviewTool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewTool.swift; sourceTree = "<group>"; };
@ -540,20 +551,23 @@
1929B714EB137AE448CE8ABD /* MainWindow+Delegates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MainWindow+Delegates.swift"; sourceTree = "<group>"; };
1929B71A92C24FEFE79A851E /* OpenQuicklyWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyWindow.swift; sourceTree = "<group>"; };
1929B71B4BB6550F5BC6D4CF /* MainWindow+CustomTitle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MainWindow+CustomTitle.swift"; sourceTree = "<group>"; };
1929B77CD37F201AEDD6E703 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = "../../third-party/libag/include/config.h"; sourceTree = "<group>"; };
1929B7A68B7109CEFAF105E8 /* AppDelegateReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegateReducer.swift; sourceTree = "<group>"; };
1929B7BB3E4B3DC96284B686 /* PrefUtilsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefUtilsTest.swift; sourceTree = "<group>"; };
1929B7CB4863F80230C32D3C /* FileItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItem.swift; sourceTree = "<group>"; };
1929B7F7A4B3FD52263D211D /* Defs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Defs.swift; sourceTree = "<group>"; };
1929B8042AC566CDF6C998A3 /* FileUtilsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtilsTest.swift; sourceTree = "<group>"; };
1929B8241CDE58F7AAF89AE4 /* PrefUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefUtils.swift; sourceTree = "<group>"; };
1929B84E4B53B05F5434E464 /* lang.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lang.h; path = "../../third-party/libag/include/lang.h"; sourceTree = "<group>"; };
1929B85023B042C485409CE1 /* HtmlPreviewTool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HtmlPreviewTool.swift; sourceTree = "<group>"; };
1929B88B5FA08E897A3C2168 /* KeysPrefReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeysPrefReducer.swift; sourceTree = "<group>"; };
1929B8EF9A9F5ACC175452BD /* PreviewUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewUtils.swift; sourceTree = "<group>"; };
1929B93256AF7F9137223E36 /* DefaultShortcuts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultShortcuts.swift; sourceTree = "<group>"; };
1929B9355C892BEBA7496C71 /* DictionaryCommonsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryCommonsTest.swift; sourceTree = "<group>"; };
1929B9695325580C7100B44C /* ignore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ignore.h; path = "../../third-party/libag/include/ignore.h"; sourceTree = "<group>"; };
1929B98192F6873508F8D76A /* FileItem+CoreDataClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "FileItem+CoreDataClass.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>"; };
1929BA43449BA41666CD55ED /* BufferList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BufferList.swift; sourceTree = "<group>"; };
1929BA5854064776A5C38257 /* decompress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = decompress.h; path = "../../third-party/libag/include/decompress.h"; sourceTree = "<group>"; };
1929BA5C7099CDEB04B76BA4 /* FileBrowser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileBrowser.swift; sourceTree = "<group>"; };
1929BA8AC40B901B20F20B71 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
1929BADEB143008EFA6F3318 /* NetUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetUtils.h; sourceTree = "<group>"; };
@ -561,7 +575,7 @@
1929BB2AD21A10A0ECA66A5E /* ToolsPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolsPref.swift; sourceTree = "<group>"; };
1929BB55946DAEBF55D24048 /* GeneralPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralPref.swift; sourceTree = "<group>"; };
1929BB6608B4F0E037CA0F4C /* States.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = States.swift; sourceTree = "<group>"; };
1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemIgnorePatternTest.swift; sourceTree = "<group>"; };
1929BB75BEF0ADFD00619A45 /* scandir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = scandir.h; path = "../../third-party/libag/include/scandir.h"; sourceTree = "<group>"; };
1929BBE0A534F2F6009D31BE /* AdvencedPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvencedPref.swift; sourceTree = "<group>"; };
1929BBF0944940845485A512 /* RpcEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RpcEvents.swift; sourceTree = "<group>"; };
1929BC2F05E9A5C0DB039739 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
@ -572,19 +586,15 @@
1929BD83A13BF133741766CC /* MainWindowReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindowReducer.swift; sourceTree = "<group>"; };
1929BDC3F82CB4CB4FE56D1B /* ImageAndTextTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageAndTextTableCell.swift; sourceTree = "<group>"; };
1929BDC8F5D48578A90236E9 /* FileBrowserReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileBrowserReducer.swift; sourceTree = "<group>"; };
1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScoredFileItem.swift; sourceTree = "<group>"; };
1929BE168F31344B69E61B62 /* PrefWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefWindow.swift; sourceTree = "<group>"; };
1929BE37AA2843779CAFA76F /* PreviewReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewReducer.swift; sourceTree = "<group>"; };
1929BE5AEA3D0980860EED50 /* HtmlPreviewToolReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HtmlPreviewToolReducer.swift; sourceTree = "<group>"; };
1929BE6AB18FA655A8A9DA73 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = util.h; path = "../../third-party/libag/include/util.h"; sourceTree = "<group>"; };
1929BE867BD8F0ED0246CC94 /* OSLogCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLogCommons.swift; sourceTree = "<group>"; };
1929BED01F5D94BFCA4CF80F /* AppearancePrefReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppearancePrefReducer.swift; sourceTree = "<group>"; };
1929BEDE7F92BC7B49E802AF /* OpenQuicklyFilterOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyFilterOperation.swift; sourceTree = "<group>"; };
1929BEEB33113B0E33C3830F /* Matcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matcher.swift; sourceTree = "<group>"; };
1929BF230875DED6CD7AB3EB /* ShortcutItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutItem.swift; sourceTree = "<group>"; };
1929BF69B01107F358CF7EAD /* ScorerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScorerTest.swift; sourceTree = "<group>"; };
1929BFB0F294F3714D5E095F /* PreviewToolReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewToolReducer.swift; sourceTree = "<group>"; };
1929BFC0A5A9C6DB09BE1368 /* Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = "<group>"; };
1929BFE179BCA3C75A13D71B /* MatcherTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MatcherTests.swift; sourceTree = "<group>"; };
4B004BCB21063B600043A396 /* DictionaryDecoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DictionaryDecoder.swift; path = ../../Carthage/Checkouts/DictionaryCoding/Sources/DictionaryCoding/DictionaryDecoder.swift; sourceTree = "<group>"; };
4B004BCC21063B600043A396 /* DictionaryCodingKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DictionaryCodingKey.swift; path = ../../Carthage/Checkouts/DictionaryCoding/Sources/DictionaryCoding/DictionaryCodingKey.swift; sourceTree = "<group>"; };
4B004BCD21063B600043A396 /* DictionaryEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DictionaryEncoder.swift; path = ../../Carthage/Checkouts/DictionaryCoding/Sources/DictionaryCoding/DictionaryEncoder.swift; sourceTree = "<group>"; };
@ -701,6 +711,19 @@
4BF18C381FD2E2AB00DF95D1 /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = ../Carthage/Build/Mac/RxCocoa.framework; sourceTree = "<group>"; };
4BF18C491FD2E2DE00DF95D1 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = ../Carthage/Build/Mac/Nimble.framework; sourceTree = "<group>"; };
4BF18C501FD2E4F200DF95D1 /* RxTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxTest.framework; path = ../Carthage/Build/Mac/RxTest.framework; sourceTree = "<group>"; };
4BF70EBF23D1B3F9009E51E9 /* FuzzyMatcher.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = FuzzyMatcher.mm; path = FuzzyMatcher/FuzzyMatcher.mm; sourceTree = "<group>"; };
4BF70EC123D1B3F9009E51E9 /* FuzzyMatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FuzzyMatcher.h; path = FuzzyMatcher/FuzzyMatcher.h; sourceTree = "<group>"; };
4BF70EC323D1B3F9009E51E9 /* FuzzyMatcherPool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FuzzyMatcherPool.swift; path = FuzzyMatcher/FuzzyMatcherPool.swift; sourceTree = "<group>"; };
4BF70ED023D1B4AF009E51E9 /* FoundationCommons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FoundationCommons.h; sourceTree = "<group>"; };
4BF70ED123D1B4AF009E51E9 /* FoundationCommons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FoundationCommons.m; sourceTree = "<group>"; };
4BF70ED423D1B54F009E51E9 /* ScoredUrl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScoredUrl.h; sourceTree = "<group>"; };
4BF70ED523D1B54F009E51E9 /* ScoredUrl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScoredUrl.m; sourceTree = "<group>"; };
4BF70EDF23D1B5B3009E51E9 /* FileScanBaton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileScanBaton.m; sourceTree = "<group>"; };
4BF70EE023D1B5B3009E51E9 /* FileScanBaton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileScanBaton.h; sourceTree = "<group>"; };
4BF70EE323D1B5EC009E51E9 /* FuzzySearchService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FuzzySearchService.swift; sourceTree = "<group>"; };
4BF70EE423D1B5EC009E51E9 /* FuzzySearchFileMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FuzzySearchFileMonitor.swift; sourceTree = "<group>"; };
4BF70EE923D1B5FF009E51E9 /* CoreDataStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataStack.swift; sourceTree = "<group>"; };
4BF70EEC23D1B618009E51E9 /* ConditionVariable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConditionVariable.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -769,12 +792,28 @@
name = "File Browser";
sourceTree = "<group>";
};
1929B180CD479C16EE70BE41 /* the_silver_searcher */ = {
isa = PBXGroup;
children = (
1929B77CD37F201AEDD6E703 /* config.h */,
1929BA5854064776A5C38257 /* decompress.h */,
1929B9695325580C7100B44C /* ignore.h */,
1929B84E4B53B05F5434E464 /* lang.h */,
1929B0EA67C53B49B98182CA /* log.h */,
1929B13F14CABB7BDCD16B5D /* options.h */,
1929B13E47E7D20EA99EDF92 /* print.h */,
1929BB75BEF0ADFD00619A45 /* scandir.h */,
1929B0A888EA54E5C8FD04C7 /* search.h */,
1929B14F9B30D4A3FA1871A9 /* uthash.h */,
1929BE6AB18FA655A8A9DA73 /* util.h */,
);
name = the_silver_searcher;
sourceTree = "<group>";
};
1929B275B9921DA7503A1932 /* Utils */ = {
isa = PBXGroup;
children = (
1929B8042AC566CDF6C998A3 /* FileUtilsTest.swift */,
1929BFE179BCA3C75A13D71B /* MatcherTests.swift */,
1929BF69B01107F358CF7EAD /* ScorerTest.swift */,
1929B7BB3E4B3DC96284B686 /* PrefUtilsTest.swift */,
);
name = Utils;
@ -847,6 +886,18 @@
name = Commons;
sourceTree = "<group>";
};
1929BA1E1547FE22A342BFD4 /* Core Data */ = {
isa = PBXGroup;
children = (
1929B17B1BC7CA08DC76495C /* FileItem+CoreDataProperties.m */,
1929B1534B8857C519D7C0FB /* FileItem+CoreDataProperties.h */,
1929B98192F6873508F8D76A /* FileItem+CoreDataClass.m */,
1929B0E63986F95E2F8DFF21 /* FileItem+CoreDataClass.h */,
1929B656C04BA6F950BFA2F5 /* FuzzySearch.xcdatamodel */,
);
name = "Core Data";
sourceTree = "<group>";
};
1929BA652D3B88FC071531EC /* UI */ = {
isa = PBXGroup;
children = (
@ -861,6 +912,15 @@
name = UI;
sourceTree = "<group>";
};
1929BAD7FC1CCB6E95D6C098 /* ccls */ = {
isa = PBXGroup;
children = (
1929B1B01340283D6AAD6B06 /* fuzzy_match.cc */,
1929B672CE187B4D3EA1D3EE /* fuzzy_match.hh */,
);
name = ccls;
sourceTree = "<group>";
};
1929BB4CF1C1FFEE6CCDD6FD /* Preferences */ = {
isa = PBXGroup;
children = (
@ -905,7 +965,6 @@
isa = PBXGroup;
children = (
1929B71A92C24FEFE79A851E /* OpenQuicklyWindow.swift */,
1929BEDE7F92BC7B49E802AF /* OpenQuicklyFilterOperation.swift */,
1929B1558455B3A74D93EF2A /* OpenQuicklyFileViewRow.swift */,
1929BDC3F82CB4CB4FE56D1B /* ImageAndTextTableCell.swift */,
);
@ -1080,6 +1139,8 @@
4BDF50101D760AB700D8FBC3 /* Commons */ = {
isa = PBXGroup;
children = (
4BF70ED023D1B4AF009E51E9 /* FoundationCommons.h */,
4BF70ED123D1B4AF009E51E9 /* FoundationCommons.m */,
4B3CF02F224B7EAC00FA9833 /* RxSwiftCommons.swift */,
4B6A70931D60E04200E12030 /* AppKitCommons.swift */,
1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */,
@ -1089,16 +1150,6 @@
name = Commons;
sourceTree = "<group>";
};
4BDF50111D760B1100D8FBC3 /* File Items */ = {
isa = PBXGroup;
children = (
1929B7CB4863F80230C32D3C /* FileItem.swift */,
1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */,
1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */,
);
name = "File Items";
sourceTree = "<group>";
};
4BEBA4FC1CFF374B00673FDF = {
isa = PBXGroup;
children = (
@ -1125,12 +1176,12 @@
4BEBA5071CFF374B00673FDF /* VimR */ = {
isa = PBXGroup;
children = (
4BF70ECB23D1B40A009E51E9 /* Fuzzy Search */,
4BB4CCEE224A7E6D00474C79 /* FSEvents */,
4B004BCA21063B4D0043A396 /* DictionaryCoding */,
4B2A2C0D1D0353750074CE9A /* Bridge.h */,
4B238BE01D3BF24200CBDD98 /* Application.swift */,
4BEBA5081CFF374B00673FDF /* AppDelegate.swift */,
4BDF50111D760B1100D8FBC3 /* File Items */,
4BF8EED91D858C4400CAC08A /* Utils */,
4BDF50101D760AB700D8FBC3 /* Commons */,
4B6423941D8EFD6100FC78C8 /* Workspace */,
@ -1147,7 +1198,6 @@
isa = PBXGroup;
children = (
4BEBA51A1CFF374B00673FDF /* Info.plist */,
1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */,
1929B41F745CDCDFE09ACDCF /* resources */,
1929B79B3F03D2E050438074 /* Commons */,
1929B275B9921DA7503A1932 /* Utils */,
@ -1155,17 +1205,35 @@
path = VimRTests;
sourceTree = "<group>";
};
4BF70ECB23D1B40A009E51E9 /* Fuzzy Search */ = {
isa = PBXGroup;
children = (
4BF70EE923D1B5FF009E51E9 /* CoreDataStack.swift */,
4BF70EE423D1B5EC009E51E9 /* FuzzySearchFileMonitor.swift */,
4BF70EE323D1B5EC009E51E9 /* FuzzySearchService.swift */,
4BF70ED423D1B54F009E51E9 /* ScoredUrl.h */,
4BF70ED523D1B54F009E51E9 /* ScoredUrl.m */,
4BF70EC123D1B3F9009E51E9 /* FuzzyMatcher.h */,
4BF70EBF23D1B3F9009E51E9 /* FuzzyMatcher.mm */,
4BF70EC323D1B3F9009E51E9 /* FuzzyMatcherPool.swift */,
4BF70EE023D1B5B3009E51E9 /* FileScanBaton.h */,
4BF70EDF23D1B5B3009E51E9 /* FileScanBaton.m */,
1929B180CD479C16EE70BE41 /* the_silver_searcher */,
1929BAD7FC1CCB6E95D6C098 /* ccls */,
1929BA1E1547FE22A342BFD4 /* Core Data */,
);
name = "Fuzzy Search";
sourceTree = "<group>";
};
4BF8EED91D858C4400CAC08A /* Utils */ = {
isa = PBXGroup;
children = (
4BF70EEC23D1B618009E51E9 /* ConditionVariable.swift */,
1929BA8AC40B901B20F20B71 /* FileUtils.swift */,
1929BEEB33113B0E33C3830F /* Matcher.swift */,
1929B9D510177918080BE39B /* Scorer.swift */,
1929B02440BC99C42F9EBD45 /* NetUtils.m */,
1929BADEB143008EFA6F3318 /* NetUtils.h */,
1929B6AD3396160AA2C46919 /* Debouncer.swift */,
1929B8EF9A9F5ACC175452BD /* PreviewUtils.swift */,
1929B56C8ED31834BA9D8543 /* FileItemUtils.swift */,
1929B8241CDE58F7AAF89AE4 /* PrefUtils.swift */,
);
name = Utils;
@ -1487,13 +1555,8 @@
4B2636B1223A487B00021586 /* SwiftCommons.swift in Sources */,
4B2636B2223A487B00021586 /* AppDelegate.swift in Sources */,
4B2636B3223A487B00021586 /* WorkspaceTool.swift in Sources */,
4B2636B4223A487B00021586 /* FileItem.swift in Sources */,
4B2636B5223A487B00021586 /* FileItemIgnorePattern.swift in Sources */,
4B2636B6223A487B00021586 /* DictionaryErrors.swift in Sources */,
4B2636B7223A487B00021586 /* FileUtils.swift in Sources */,
4B2636B8223A487B00021586 /* Matcher.swift in Sources */,
4B2636B9223A487B00021586 /* ScoredFileItem.swift in Sources */,
4B2636BA223A487B00021586 /* Scorer.swift in Sources */,
4B2636BB223A487B00021586 /* ProxyWorkspaceBar.swift in Sources */,
4B2636BC223A487B00021586 /* FoundationCommons.swift in Sources */,
4B2636BD223A487B00021586 /* NetUtils.m in Sources */,
@ -1503,6 +1566,8 @@
4B2636C1223A487B00021586 /* UiRoot.swift in Sources */,
4B2636C2223A487B00021586 /* UiRootReducer.swift in Sources */,
4B2636C3223A487B00021586 /* MainWindowReducer.swift in Sources */,
4BF70ED723D1B54F009E51E9 /* ScoredUrl.m in Sources */,
4BF70EC923D1B3F9009E51E9 /* FuzzyMatcherPool.swift in Sources */,
4B2636C4223A487B00021586 /* PreviewTool.swift in Sources */,
4B917E612334D52D00752149 /* EonilFSEvents.swift in Sources */,
4B2636C5223A487B00021586 /* PreviewReducer.swift in Sources */,
@ -1512,6 +1577,7 @@
4B2636C9223A487B00021586 /* PreviewToolReducer.swift in Sources */,
4B2636CA223A487B00021586 /* Types.swift in Sources */,
4B2636CB223A487B00021586 /* OpenQuicklyReducer.swift in Sources */,
4BF70EE223D1B5B3009E51E9 /* FileScanBaton.m in Sources */,
4B917E582334D52D00752149 /* EonilFSEventStreamCreateFlags.swift in Sources */,
4B2636CC223A487B00021586 /* FileMonitorReducer.swift in Sources */,
4B2636CD223A487B00021586 /* FileMonitor.swift in Sources */,
@ -1520,6 +1586,7 @@
4B2636D0223A487B00021586 /* BufferListReducer.swift in Sources */,
4B2636D1223A487B00021586 /* PrefWindow.swift in Sources */,
4B917E552334D52D00752149 /* EonilFSEventStream.swift in Sources */,
4BF70EE823D1B5EC009E51E9 /* FuzzySearchFileMonitor.swift in Sources */,
4B2636D2223A487B00021586 /* PrefPane.swift in Sources */,
4B2636D3223A487B00021586 /* GeneralPref.swift in Sources */,
4B917E522334D52D00752149 /* EonilFSEventStreamEventFlags.swift in Sources */,
@ -1532,18 +1599,19 @@
4B2636D9223A487B00021586 /* AdvencedPref.swift in Sources */,
4B2636DA223A487B00021586 /* AppearancePrefReducer.swift in Sources */,
4B2636DB223A487B00021586 /* OpenQuicklyWindow.swift in Sources */,
4B2636DC223A487B00021586 /* OpenQuicklyFilterOperation.swift in Sources */,
4B2636DD223A487B00021586 /* OpenQuicklyFileViewRow.swift in Sources */,
4BF70EEB23D1B5FF009E51E9 /* CoreDataStack.swift in Sources */,
4B2636DE223A487B00021586 /* PrefMiddleware.swift in Sources */,
4B2636DF223A487B00021586 /* Debouncer.swift in Sources */,
4B2636E0223A487B00021586 /* PreviewUtils.swift in Sources */,
4B2636E1223A487B00021586 /* FileItemUtils.swift in Sources */,
4B2636E2223A487B00021586 /* HtmlPreviewTool.swift in Sources */,
4B2636E3223A487B00021586 /* HtmlPreviewToolReducer.swift in Sources */,
4BF70ED323D1B4AF009E51E9 /* FoundationCommons.m in Sources */,
4B2636E4223A487B00021586 /* AdvancedPrefReducer.swift in Sources */,
4B2636E5223A487B00021586 /* ToolsPref.swift in Sources */,
4B2636E6223A487B00021586 /* ToolsPrefReducer.swift in Sources */,
4B2636E7223A487B00021586 /* PrefUtils.swift in Sources */,
4BF70EC523D1B3F9009E51E9 /* FuzzyMatcher.mm in Sources */,
4B917E642334D52D00752149 /* EonilFSEventStreamEventID.swift in Sources */,
4B2636E8223A487B00021586 /* ThemedTableSubviews.swift in Sources */,
4B2636E9223A487B00021586 /* ImageAndTextTableCell.swift in Sources */,
@ -1562,12 +1630,16 @@
4B2636F4223A487B00021586 /* ShortcutsPref.swift in Sources */,
4B2636F5223A487B00021586 /* ShortcutsTableSubviews.swift in Sources */,
4B2636F6223A487B00021586 /* DefaultShortcuts.swift in Sources */,
4BF70EE623D1B5EC009E51E9 /* FuzzySearchService.swift in Sources */,
4B2636F7223A487B00021586 /* ShortcutItem.swift in Sources */,
4B2636F8223A487B00021586 /* RpcEvents.swift in Sources */,
4B2636F9223A487B00021586 /* RpcAppearanceEpic.swift in Sources */,
4BF70EEE23D1B619009E51E9 /* ConditionVariable.swift in Sources */,
4B2636FA223A487B00021586 /* OSLogCommons.swift in Sources */,
4B2636FB223A487B00021586 /* Defs.swift in Sources */,
1929B179DBDE58A9D9BCA819 /* MainWindow+Types.swift in Sources */,
1929BAEE911EC7620EE51911 /* fuzzy_match.cc in Sources */,
1929B543D5C82485F053CF17 /* FuzzySearch.xcdatamodel in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1585,13 +1657,8 @@
4B6A70961D6100E300E12030 /* SwiftCommons.swift in Sources */,
4BEBA5091CFF374B00673FDF /* AppDelegate.swift in Sources */,
4B64239A1D8EFE3000FC78C8 /* WorkspaceTool.swift in Sources */,
1929B462CD4935AFF6D69457 /* FileItem.swift in Sources */,
1929B6388EAF16C190B82955 /* FileItemIgnorePattern.swift in Sources */,
4B004BD521063B600043A396 /* DictionaryErrors.swift in Sources */,
1929B67DA3EB21A631EF1DBB /* FileUtils.swift in Sources */,
1929B3F5743967125F357C9F /* Matcher.swift in Sources */,
1929B53876E6952D378C2B30 /* ScoredFileItem.swift in Sources */,
1929BD3F9E609BFADB27584B /* Scorer.swift in Sources */,
4BB409EE1DDA77E9005F39A2 /* ProxyWorkspaceBar.swift in Sources */,
1929B0E0C3BC59F52713D5A2 /* FoundationCommons.swift in Sources */,
1929BD2F41D93ADFF43C1C98 /* NetUtils.m in Sources */,
@ -1601,6 +1668,8 @@
1929BAFF1E011321D3186EE6 /* UiRoot.swift in Sources */,
1929B29B95AD176D57942E08 /* UiRootReducer.swift in Sources */,
1929BB4A9B2FA42A64CCCC76 /* MainWindowReducer.swift in Sources */,
4BF70ED623D1B54F009E51E9 /* ScoredUrl.m in Sources */,
4BF70EC823D1B3F9009E51E9 /* FuzzyMatcherPool.swift in Sources */,
1929B8FB248D71BF88A35761 /* PreviewTool.swift in Sources */,
4B917E5F2334D52D00752149 /* EonilFSEvents.swift in Sources */,
1929B4B70926DE113E6BF990 /* PreviewReducer.swift in Sources */,
@ -1610,6 +1679,7 @@
1929B3AC66EFE35D68C020E3 /* PreviewToolReducer.swift in Sources */,
1929B59FA5C286E010F70BEE /* Types.swift in Sources */,
1929B6D8F5FC723B7109031F /* OpenQuicklyReducer.swift in Sources */,
4BF70EE123D1B5B3009E51E9 /* FileScanBaton.m in Sources */,
4B917E562334D52D00752149 /* EonilFSEventStreamCreateFlags.swift in Sources */,
1929B5543B1E31A26096E656 /* FileMonitorReducer.swift in Sources */,
1929B5F016431A76292D1E84 /* FileMonitor.swift in Sources */,
@ -1618,6 +1688,7 @@
1929B4E54E2F13A7F5F2B682 /* BufferListReducer.swift in Sources */,
1929BAE4900D72A7877741B1 /* PrefWindow.swift in Sources */,
4B917E532334D52D00752149 /* EonilFSEventStream.swift in Sources */,
4BF70EE723D1B5EC009E51E9 /* FuzzySearchFileMonitor.swift in Sources */,
1929BEAE0592096BC1191B67 /* PrefPane.swift in Sources */,
1929BEDE1BE950EDA9497363 /* GeneralPref.swift in Sources */,
4B917E502334D52D00752149 /* EonilFSEventStreamEventFlags.swift in Sources */,
@ -1630,18 +1701,19 @@
1929B50D933A369A86A165DE /* AdvencedPref.swift in Sources */,
1929BCC7908DD899999B70BE /* AppearancePrefReducer.swift in Sources */,
1929B3557317755A43513B17 /* OpenQuicklyWindow.swift in Sources */,
1929B333855A5406C400DA92 /* OpenQuicklyFilterOperation.swift in Sources */,
1929B1837C750CADB3A5BCB9 /* OpenQuicklyFileViewRow.swift in Sources */,
4BF70EEA23D1B5FF009E51E9 /* CoreDataStack.swift in Sources */,
1929B990A143763A56CFCED0 /* PrefMiddleware.swift in Sources */,
1929BA76A1D97D8226F7CFB1 /* Debouncer.swift in Sources */,
1929B71610FF1DC6E459BA49 /* PreviewUtils.swift in Sources */,
1929B94083273D4B321AD848 /* FileItemUtils.swift in Sources */,
1929BFDE22D155F7C4B19E96 /* HtmlPreviewTool.swift in Sources */,
1929B4B00D7BB191A9A6532D /* HtmlPreviewToolReducer.swift in Sources */,
4BF70ED223D1B4AF009E51E9 /* FoundationCommons.m in Sources */,
1929BCF7F7B9CC5499A3F506 /* AdvancedPrefReducer.swift in Sources */,
1929BF03FD6465F289AA80B2 /* ToolsPref.swift in Sources */,
1929B6C0393DE40E34F4A49A /* ToolsPrefReducer.swift in Sources */,
1929B542A071BD03C846F6EF /* PrefUtils.swift in Sources */,
4BF70EC423D1B3F9009E51E9 /* FuzzyMatcher.mm in Sources */,
4B917E622334D52D00752149 /* EonilFSEventStreamEventID.swift in Sources */,
1929BE2F3E0182CC51F2763A /* ThemedTableSubviews.swift in Sources */,
1929B6460862447A31B5B082 /* ImageAndTextTableCell.swift in Sources */,
@ -1660,12 +1732,16 @@
1929BB85B2D30E548A32663D /* ShortcutsPref.swift in Sources */,
1929BA269EBD68251410A08E /* ShortcutsTableSubviews.swift in Sources */,
1929B2D56C4652E251C23AD4 /* DefaultShortcuts.swift in Sources */,
4BF70EE523D1B5EC009E51E9 /* FuzzySearchService.swift in Sources */,
1929B0C7150100A84FBDB8BF /* ShortcutItem.swift in Sources */,
1929B250DB3FB395A700FE8C /* RpcEvents.swift in Sources */,
1929BF3253594E5B1908C6CE /* RpcAppearanceEpic.swift in Sources */,
4BF70EED23D1B618009E51E9 /* ConditionVariable.swift in Sources */,
1929B4E8B916008399CD5D3A /* OSLogCommons.swift in Sources */,
1929B5A0EDD1119CFF7BB84C /* Defs.swift in Sources */,
1929B376DB09AB5FDBF42BA1 /* MainWindow+Types.swift in Sources */,
1929B443B7AB2176A7818CA1 /* fuzzy_match.cc in Sources */,
1929BF5D0EFCC56A733BB4B7 /* FuzzySearch.xcdatamodel in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1674,18 +1750,14 @@
buildActionMask = 2147483647;
files = (
4B6DFB3A22366D140066BB43 /* OSLogCommons.swift in Sources */,
4B96FB3B1EBBC56F00E4E164 /* FileItemIgnorePattern.swift in Sources */,
4B96FB3C1EBBC56F00E4E164 /* FileUtils.swift in Sources */,
4B917E572334D52D00752149 /* EonilFSEventStreamCreateFlags.swift in Sources */,
4B96FB3D1EBBC56F00E4E164 /* Matcher.swift in Sources */,
4B96FB3E1EBBC56F00E4E164 /* Scorer.swift in Sources */,
4B004BD621063B600043A396 /* DictionaryErrors.swift in Sources */,
4B96FB3F1EBBC56F00E4E164 /* PrefUtils.swift in Sources */,
4B96FB401EBBC56F00E4E164 /* FoundationCommons.swift in Sources */,
4B004BD021063B600043A396 /* DictionaryDecoder.swift in Sources */,
4B96FB421EBBC56F00E4E164 /* SwiftCommons.swift in Sources */,
4B3CF031224B7EAC00FA9833 /* RxSwiftCommons.swift in Sources */,
1929BEFEABA0448306CDB6D4 /* FileItemIgnorePatternTest.swift in Sources */,
1929B66F795867B8C07FAAD4 /* DictionaryCommonsTest.swift in Sources */,
4B004BD221063B600043A396 /* DictionaryCodingKey.swift in Sources */,
4B917E542334D52D00752149 /* EonilFSEventStream.swift in Sources */,
@ -1697,9 +1769,7 @@
1929BF4FF30D9A9DE82C3052 /* FileUtilsTest.swift in Sources */,
4B917E4E2334D52D00752149 /* EonilFSEventStreamError.swift in Sources */,
4B917E632334D52D00752149 /* EonilFSEventStreamEventID.swift in Sources */,
1929BFC70581084B5CE04A5B /* MatcherTests.swift in Sources */,
4B917E602334D52D00752149 /* EonilFSEvents.swift in Sources */,
1929BAAD7336FDFF1F78E749 /* ScorerTest.swift in Sources */,
4B917E512334D52D00752149 /* EonilFSEventStreamEventFlags.swift in Sources */,
4B004BD421063B600043A396 /* DictionaryEncoder.swift in Sources */,
1929B8E90A1378E494D481E7 /* PrefUtilsTest.swift in Sources */,
@ -1783,8 +1853,18 @@
"$(inherited)",
"$(PROJECT_DIR)/../Carthage/Build/Mac",
);
HEADER_SEARCH_PATHS = (
"$(PROJECT_DIR)/../third-party/libxz/include",
"$(PROJECT_DIR)/../third-party/libpcre/include",
);
INFOPLIST_FILE = "$(SRCROOT)/VimR.dev.Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_LDFLAGS = (
"$(PROJECT_DIR)/../third-party/libxz/lib/liblzma.a",
"$(PROJECT_DIR)/../third-party/libpcre/lib/libpcre.a",
"$(PROJECT_DIR)/../third-party/libag/lib/libag.a",
"-pthread",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR.dev;
PRODUCT_MODULE_NAME = VimR;
PRODUCT_NAME = "VimR-dev";
@ -1803,8 +1883,18 @@
"$(inherited)",
"$(PROJECT_DIR)/../Carthage/Build/Mac",
);
HEADER_SEARCH_PATHS = (
"$(PROJECT_DIR)/../third-party/libxz/include",
"$(PROJECT_DIR)/../third-party/libpcre/include",
);
INFOPLIST_FILE = "$(SRCROOT)/VimR.dev.Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_LDFLAGS = (
"$(PROJECT_DIR)/../third-party/libxz/lib/liblzma.a",
"$(PROJECT_DIR)/../third-party/libpcre/lib/libpcre.a",
"$(PROJECT_DIR)/../third-party/libag/lib/libag.a",
"-pthread",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR.dev;
PRODUCT_MODULE_NAME = VimR;
PRODUCT_NAME = "VimR-dev";
@ -1842,7 +1932,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 330;
CURRENT_PROJECT_VERSION = 331;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -1903,7 +1993,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 330;
CURRENT_PROJECT_VERSION = 331;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_NS_ASSERTIONS = NO;
@ -1937,8 +2027,18 @@
"$(inherited)",
"$(PROJECT_DIR)/../Carthage/Build/Mac",
);
HEADER_SEARCH_PATHS = (
"$(PROJECT_DIR)/../third-party/libxz/include",
"$(PROJECT_DIR)/../third-party/libpcre/include",
);
INFOPLIST_FILE = VimR/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_LDFLAGS = (
"$(PROJECT_DIR)/../third-party/libxz/lib/liblzma.a",
"$(PROJECT_DIR)/../third-party/libpcre/lib/libpcre.a",
"$(PROJECT_DIR)/../third-party/libag/lib/libag.a",
"-pthread",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR;
PRODUCT_NAME = VimR;
SWIFT_OBJC_BRIDGING_HEADER = VimR/Bridge.h;
@ -1955,8 +2055,18 @@
"$(inherited)",
"$(PROJECT_DIR)/../Carthage/Build/Mac",
);
HEADER_SEARCH_PATHS = (
"$(PROJECT_DIR)/../third-party/libxz/include",
"$(PROJECT_DIR)/../third-party/libpcre/include",
);
INFOPLIST_FILE = VimR/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_LDFLAGS = (
"$(PROJECT_DIR)/../third-party/libxz/lib/liblzma.a",
"$(PROJECT_DIR)/../third-party/libpcre/lib/libpcre.a",
"$(PROJECT_DIR)/../third-party/libag/lib/libag.a",
"-pthread",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.VimR;
PRODUCT_NAME = VimR;
SWIFT_OBJC_BRIDGING_HEADER = VimR/Bridge.h;

View File

@ -90,9 +90,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
self.setSparkleUrl(self.useSnapshot)
}
if appState.quit {
NSApp.terminate(self)
}
if appState.quit { NSApp.terminate(self) }
})
.disposed(by: self.disposeBag)
}
@ -169,7 +167,21 @@ extension AppDelegate {
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
self.context.savePrefs()
if self.hasDirtyWindows && self.hasMainWindows {
guard self.hasMainWindows else {
self.uiRoot?.prepareQuit()
return .terminateNow
}
// check first whether there are blocked nvim instances, if so, abort and inform the user
if self.uiRoot?.hasBlockedWindows() == true {
let alert = NSAlert()
alert.messageText = "There are windows waiting for your input."
alert.alertStyle = .informational
alert.runModal()
return .terminateCancel
}
if self.hasDirtyWindows {
let alert = NSAlert()
alert.addButton(withTitle: "Cancel")
let discardAndQuitButton = alert.addButton(withTitle: "Discard and Quit")
@ -187,13 +199,8 @@ extension AppDelegate {
return .terminateCancel
}
if self.hasMainWindows {
self.updateMainWindowTemplateBeforeQuitting()
self.uiRoot?.prepareQuit()
return .terminateNow
}
// There are no open main window, then just quit.
self.updateMainWindowTemplateBeforeQuitting()
self.uiRoot?.prepareQuit()
return .terminateNow
}
@ -209,8 +216,7 @@ extension AppDelegate {
}
private func updateMainWindowTemplateBeforeQuitting() {
guard let uuid = self.context.state.currentMainWindowUuid,
let curMainWindow = self.context.state.mainWindows[uuid] else { return }
guard let curMainWindow = self.context.state.currentMainWindow else { return }
self.context.state.mainWindowTemplate = curMainWindow
self.context.savePrefs()

View File

@ -60,6 +60,7 @@ class AppDelegateReducer: ReducerType {
)
mainWindow.preview.server = self.baseServerUrl.appendingPathComponent(MarkdownReducer.nonePath)
mainWindow.usesVcsIgnores = state.openQuickly.defaultUsesVcsIgnores
mainWindow.nvimArgs = config.nvimArgs
mainWindow.cliPipePath = config.cliPipePath
mainWindow.envDict = config.envDict

View File

@ -231,6 +231,17 @@ extension NSOutlineView {
}
}
extension NSTextField {
static func defaultTitleTextField() -> NSTextField {
let field = NSTextField(forAutoLayout: ())
field.backgroundColor = NSColor.clear;
field.isEditable = false;
field.isBordered = false;
return field
}
}
extension NSScrollView {
static func standardScrollView() -> NSScrollView {

View File

@ -1,5 +1,5 @@
{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf200
{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;}
{\rtf1\ansi\ansicpg1252\cocoartf2511
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;}
{\colortbl;\red255\green255\blue255;}
{\*\expandedcolortbl;;}
\paperw11900\paperh16840\vieww10960\viewh15520\viewkind0
@ -105,6 +105,18 @@ By:
{\field{\*\fldinst{HYPERLINK "https://github.com/Kentzo/ShortcutRecorder"}}{\fldrslt https://github.com/Kentzo/ShortcutRecorder}}\
\
\f1\b ccls\
{\field{\*\fldinst{HYPERLINK "https://github.com/MaskRay/ccls"}}{\fldrslt
\f0\b0 https://github.com/MaskRay/ccls}}
\f0\b0 \
\
\f1\b The Silver Searcher\
{\field{\*\fldinst{HYPERLINK "https://github.com/ggreer/the_silver_searcher"}}{\fldrslt
\f0\b0 https://github.com/ggreer/the_silver_searcher}}
\f0\b0 \
\
\f1\b Nimble
\f0\b0 \
{\field{\*\fldinst{HYPERLINK "https://github.com/Quick/Nimble"}}{\fldrslt https://github.com/Quick/Nimble}}\

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSWindowController">
@ -12,12 +13,12 @@
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Open Quickly" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="38.open-quickly-window.frame" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" texturedBackground="YES"/>
<window title="Open Quickly" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="38.open-quickly-window.frame" animationBehavior="default" titlebarAppearsTransparent="YES" titleVisibility="hidden" id="QvC-M9-y7g" customClass="TitlelessKeyWindow" customModule="VimR" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" fullSizeContentView="YES"/>
<windowCollectionBehavior key="collectionBehavior" fullScreenAuxiliary="YES"/>
<windowPositionMask key="initialPositionMask" topStrut="YES"/>
<rect key="contentRect" x="196" y="420" width="365" height="255"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<value key="minFullScreenContentSize" type="size" width="200" height="255"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="365" height="255"/>

View File

@ -5,3 +5,8 @@
#import <NvimView/SharedTypes.h>
#import "NetUtils.h"
#import "FuzzyMatcher.h"
#import "FoundationCommons.h"
#import "ScoredUrl.h"
#import "FileScanBaton.h"
#import "FileItem+CoreDataProperties.h"

View File

@ -0,0 +1,38 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
class ConditionVariable {
private(set) var posted: Bool
init(posted: Bool = false) {
self.posted = posted
}
func wait(`for` seconds: TimeInterval, then fn: (() -> Void)? = nil) {
self.condition.lock()
defer { self.condition.unlock() }
while !self.posted {
self.condition.wait(until: Date(timeIntervalSinceNow: seconds))
}
fn?()
}
func broadcast(then fn: (() -> Void)? = nil) {
self.condition.lock()
defer { self.condition.unlock() }
self.posted = true
self.condition.broadcast()
fn?()
}
private let condition = NSCondition()
}

View File

@ -0,0 +1,118 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import CoreData
import os
class CoreDataStack {
enum Error: Swift.Error {
case noCacheFolder
case pathDoesNotExit
case pathNotFolder
case unableToComplete(Swift.Error)
}
enum StoreLocation {
case temp(String)
case cache(String)
case path(String)
}
let container: NSPersistentContainer
let storeFile: URL
var storeLocation: URL { self.storeFile.parent }
var deleteOnDeinit: Bool
func newBackgroundContext() -> NSManagedObjectContext {
let context = self.container.newBackgroundContext()
context.undoManager = nil
return context
}
init(modelName: String, storeLocation: StoreLocation, deleteOnDeinit: Bool = false) throws {
self.deleteOnDeinit = deleteOnDeinit
self.container = NSPersistentContainer(name: modelName)
let fileManager = FileManager.default
let url: URL
switch storeLocation {
case .temp(let folderName):
let parentUrl = fileManager
.temporaryDirectory
.appendingPathComponent(folderName)
try fileManager.createDirectory(at: parentUrl, withIntermediateDirectories: true)
url = parentUrl.appendingPathComponent(modelName)
case .cache(let folderName):
guard let cacheUrl = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first else {
throw Error.noCacheFolder
}
let parentUrl = cacheUrl.appendingPathComponent(folderName)
try fileManager.createDirectory(at: parentUrl, withIntermediateDirectories: true)
url = parentUrl.appendingPathComponent(modelName)
case .path(let path):
guard fileManager.fileExists(atPath: path) else { throw Error.pathDoesNotExit }
let parentFolder = URL(fileURLWithPath: path)
guard parentFolder.isDir else { throw Error.pathNotFolder }
url = parentFolder.appendingPathComponent(modelName)
}
self.container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: url)]
self.storeFile = url
self.log.info("Created Core Data store in \(self.storeLocation)")
let condition = ConditionVariable()
var error: Swift.Error?
self.container.loadPersistentStores { _, err in
error = err
condition.broadcast()
}
condition.wait(for: 5)
if let err = error { throw Error.unableToComplete(err) }
self.container.viewContext.undoManager = nil
}
func deleteStore() throws {
guard self.deleteOnDeinit else { return }
guard let store = self.container.persistentStoreCoordinator.persistentStore(
for: self.storeFile
) else { return }
try self.container.persistentStoreCoordinator.remove(store)
let parentFolder = self.storeLocation
let fileManager = FileManager.default
guard fileManager.fileExists(atPath: parentFolder.path) else { return }
try fileManager.removeItem(at: parentFolder)
self.log.info("Deleted store at \(self.storeLocation)")
}
deinit {
guard self.deleteOnDeinit else { return }
do {
try self.deleteStore()
} catch {
self.log.error("Could not delete store at \(self.storeLocation): \(error)")
}
}
private let log = OSLog(subsystem: Defs.loggerSubsystem, category: Defs.LoggerCategory.service)
}

View File

@ -16,6 +16,7 @@ struct Defs {
static let uiComponents = "ui-components"
static let middleware = "middleware"
static let service = "service"
}
static let webViewProcessPool = WKProcessPool()

View File

@ -0,0 +1,21 @@
//
// FileItem+CoreDataClass.h
// VimR
//
// Created by Tae Won Ha on 18.01.20.
// Copyright © 2020 Tae Won Ha. All rights reserved.
//
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
NS_ASSUME_NONNULL_BEGIN
@interface FileItem : NSManagedObject
@end
NS_ASSUME_NONNULL_END
#import "FileItem+CoreDataProperties.h"

View File

@ -0,0 +1,14 @@
//
// FileItem+CoreDataClass.m
// VimR
//
// Created by Tae Won Ha on 18.01.20.
// Copyright © 2020 Tae Won Ha. All rights reserved.
//
//
#import "FileItem+CoreDataClass.h"
@implementation FileItem
@end

View File

@ -0,0 +1,39 @@
//
// FileItem+CoreDataProperties.h
// VimR
//
// Created by Tae Won Ha on 18.01.20.
// Copyright © 2020 Tae Won Ha. All rights reserved.
//
//
#import "FileItem+CoreDataClass.h"
NS_ASSUME_NONNULL_BEGIN
@interface FileItem (CoreDataProperties)
+ (NSFetchRequest<FileItem *> *)fetchRequest;
@property (nonatomic) int16_t direntType;
@property (nonatomic) BOOL isHidden;
@property (nonatomic) BOOL isPackage;
@property (nonatomic) BOOL needsScanChildren;
@property (nullable, nonatomic, copy) NSString *pathStart;
@property (nullable, nonatomic, copy) NSURL *url;
@property (nullable, nonatomic, retain) NSSet<FileItem *> *children;
@property (nullable, nonatomic, retain) FileItem *parent;
@end
@interface FileItem (CoreDataGeneratedAccessors)
- (void)addChildrenObject:(FileItem *)value;
- (void)removeChildrenObject:(FileItem *)value;
- (void)addChildren:(NSSet<FileItem *> *)values;
- (void)removeChildren:(NSSet<FileItem *> *)values;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,27 @@
//
// FileItem+CoreDataProperties.m
// VimR
//
// Created by Tae Won Ha on 18.01.20.
// Copyright © 2020 Tae Won Ha. All rights reserved.
//
//
#import "FileItem+CoreDataProperties.h"
@implementation FileItem (CoreDataProperties)
+ (NSFetchRequest<FileItem *> *)fetchRequest {
return [NSFetchRequest fetchRequestWithEntityName:@"FileItem"];
}
@dynamic direntType;
@dynamic isHidden;
@dynamic isPackage;
@dynamic needsScanChildren;
@dynamic pathStart;
@dynamic url;
@dynamic children;
@dynamic parent;
@end

View File

@ -1,59 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
class FileItem : CustomStringConvertible, Hashable, Comparable {
static func ==(left: FileItem, right: FileItem) -> Bool {
return left.url == right.url
}
static func <(left: FileItem, right: FileItem) -> Bool {
return left.url.lastPathComponent < right.url.lastPathComponent
}
let url: URL
var isDir: Bool {
return self.url.isDir
}
var isHidden: Bool {
return self.url.isHidden
}
var isPackage: Bool {
return self.url.isPackage
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.url)
}
/// 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.isDir), hidden=\(self.isHidden), package=\(self.isPackage), "
+ "needsScan=\(self.needsScanChildren), childrenScanned=\(self.childrenScanned), "
+ "ignore=\(self.ignore), ignoreToken=\(String(describing: self.ignoreToken)), "
+ "children=\(self.children.count)>"
}
init(_ url: URL) {
self.url = url
}
func child(with url: URL) -> FileItem? {
return self.children.first { $0.url == url }
}
}

View File

@ -1,87 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
private let whitespaceCharSet = CharacterSet.whitespaces
class FileItemIgnorePattern: Hashable, CustomStringConvertible {
static func ==(lhs: FileItemIgnorePattern, rhs: FileItemIgnorePattern) -> Bool {
return lhs.pattern == rhs.pattern
}
static func from(string str: String) -> Set<FileItemIgnorePattern> {
if str.trimmingCharacters(in: whitespaceCharSet).count == 0 {
return Set()
}
let patterns: [FileItemIgnorePattern] = str
.components(separatedBy: ",")
.compactMap {
let trimmed = $0.trimmingCharacters(in: whitespaceCharSet)
if trimmed.count == 0 {
return nil
}
return FileItemIgnorePattern(pattern: trimmed)
}
return Set(patterns)
}
static func toString(_ set: Set<FileItemIgnorePattern>) -> String {
return Array(set)
.map { $0.pattern }
.sorted()
.joined(separator: ", ")
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.pattern)
}
var description: String {
return "<FileItemIgnorePattern: pattern=\(self.pattern), folderPattern=\(self.folderPattern)>"
}
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>.allocate(capacity: len + 1)
memcpy(self.patternAsFileSysRep, fileSysRep, len)
self.patternAsFileSysRep[len] = 0
}
deinit {
self.patternAsFileSysRep.deallocate()
}
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
}
}

View File

@ -1,178 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
import RxSwift
class FileItemUtils {
static func flatFileItems(of url: URL,
ignorePatterns: Set<FileItemIgnorePattern>,
ignoreToken: Token,
root: FileItem) -> Observable<[FileItem]> {
guard url.isFileURL else {
return Observable.empty()
}
guard FileUtils.fileExists(at: url) else {
return Observable.empty()
}
let pathComponents = url.pathComponents
return Observable.create { observer in
let cancel = Disposables.create {
// noop
}
scanDispatchQueue.async {
guard let targetItem = fileItem(for: pathComponents, root: root) else {
observer.onCompleted()
return
}
var flatNewFileItems: [FileItem] = []
var dirStack: [FileItem] = [targetItem]
while let curItem = dirStack.popLast() {
if cancel.isDisposed {
observer.onCompleted()
return
}
if !curItem.childrenScanned || curItem.needsScanChildren {
scanChildren(curItem)
}
curItem.children
.filter { item in
if item.isHidden || item.isPackage {
return false
}
// This item already has been fnmatch'ed, thus return the cached value.
if item.ignoreToken == ignoreToken {
return !item.ignore
}
item.ignoreToken = ignoreToken
item.ignore = false
let path = item.url.path
for pattern in 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.isDir ? dirStack.append($0) : flatNewFileItems.append($0) }
if flatNewFileItems.count >= emitChunkSize {
observer.onNext(flatNewFileItems)
flatNewFileItems = []
}
}
if !cancel.isDisposed {
observer.onNext(flatNewFileItems)
observer.onCompleted()
}
}
return cancel
}
}
static func item(for url: URL, root: FileItem, create: Bool = true) -> FileItem? {
return fileItem(for: url.pathComponents, root: root, create: create)
}
static func sortedChildren(for url: URL, root: FileItem) -> [FileItem] {
guard let fileItem = fileItem(for: url, root: root) else {
return []
}
if !fileItem.childrenScanned || fileItem.needsScanChildren {
scanChildren(fileItem, sorted: true)
return fileItem.children
}
return fileItem.children.sorted()
}
}
/// When at least this much of non-directory and visible files are scanned, they are emitted.
private let emitChunkSize = 1000
private let scanDispatchQueue = DispatchQueue.global(qos: .userInitiated)
private let lock = NSRecursiveLock()
private func synced<T>(_ fn: () -> T) -> T {
lock.lock()
defer { lock.unlock() }
return fn()
}
private func fileItem(for pathComponents: [String], root: FileItem, create: Bool = true) -> FileItem? {
return synced {
pathComponents.dropFirst().reduce(root) { (resultItem, childName) -> FileItem? in
guard let parent = resultItem else {
return nil
}
return child(withName: childName, ofParent: parent, create: true)
}
}
}
private func fileItem(for url: URL, root: FileItem, create: Bool = true) -> FileItem? {
return fileItem(for: url.pathComponents, root: root, create: create)
}
/// 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.appendingPathComponent(name)
guard FileUtils.fileExists(at: childUrl) else {
return nil
}
let child = FileItem(childUrl)
synced { parent.children.append(child) }
return child
}
return filteredChildren.first
}
private func scanChildren(_ item: FileItem, sorted: Bool = false) {
let children = FileUtils.directDescendants(of: item.url).map(FileItem.init)
synced {
if sorted {
item.children = children.sorted()
} else {
item.children = children
}
item.childrenScanned = true
item.needsScanChildren = false
}
}

View File

@ -16,10 +16,6 @@ class FileMonitorReducer: ReducerType {
switch tuple.action {
case let .change(in: url):
if let fileItem = FileItemUtils.item(for: url, root: state.openQuickly.root, create: false) {
fileItem.needsScanChildren = true
}
state.mainWindows
.filter { (uuid, mainWindow) in url == mainWindow.cwd || url.isContained(in: mainWindow.cwd) }
.map { $0.0 }

23
VimR/VimR/FileScanBaton.h Normal file
View File

@ -0,0 +1,23 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Foundation/Foundation.h>
#import "ignore.h"
#import "scandir.h"
@interface FileScanBaton : NSObject
@property(readonly, nonnull) ignores *ig;
@property(readonly, nonnull) NSString *pathStart;
@property(readonly, nonnull) NSURL *url;
- (bool)test:(NSURL * _Nonnull)url;
- (instancetype _Nonnull)initWithBaseUrl:(NSURL *_Nonnull)baseUrl;
- (instancetype _Nonnull)initWithParent:(FileScanBaton *_Nonnull)parent url:(NSURL *_Nonnull)url;
@end

205
VimR/VimR/FileScanBaton.m Normal file
View File

@ -0,0 +1,205 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import "FileScanBaton.h"
#import "util.h"
#import "FoundationCommons.h"
#ifdef DEBUG
FILE *out_fd;
static dispatch_once_t debugToken;
#endif
@implementation FileScanBaton {
NSURL *_baseUrl;
scandir_baton_t *_baton;
const char *_basePathCstr;
const char *_pathStartCstr;
}
static const char *cfstr_to_cstr_copy(CFStringRef cfstr);
static void load_global_gitignores(ignores *ig);
- (bool)test:(NSURL *_Nonnull)url {
struct dirent dirent = url.fakeDirent;
return (bool) filename_filter(_baton->path_start, &dirent, _baton);
}
- (instancetype)initWithBaseUrl:(NSURL *)baseUrl {
#ifdef DEBUG
dispatch_once(&debugToken, ^{
out_fd = fopen("/Users/hat/Downloads/scan.log", "w");
set_log_level(LOG_LEVEL_DEBUG);
});
#endif
self = [super init];
if (self == nil) {return nil;}
_baseUrl = baseUrl;
_url = baseUrl;
_pathStart = @".";
_ig = init_ignore([FileScanBaton stubBatonWithGlobalGitignores].ig, "", 0);
[self initScanDirBaton];
[self loadVcsIgnores];
return self;
}
- (instancetype)initWithParent:(FileScanBaton *)parent url:(NSURL *)url {
self = [super init];
if (self == nil) {return nil;}
_baseUrl = parent.url;
_url = url;
_pathStart = [parent.pathStart stringByAppendingFormat:@"/%@", url.lastPathComponent];
const char *dirname = [url.lastPathComponent cStringUsingEncoding:NSUTF8StringEncoding];
_ig = init_ignore(parent.ig, dirname, strlen(dirname));
[self initScanDirBaton];
[self loadVcsIgnores];
return self;
}
- (void)initScanDirBaton {
_basePathCstr = (char *) cfstr_to_cstr_copy((__bridge CFStringRef) _baseUrl.path);
_pathStartCstr = (char *) cfstr_to_cstr_copy((__bridge CFStringRef) _pathStart);
_baton = malloc(sizeof(scandir_baton_t));
_baton->ig = _ig;
_baton->base_path = _basePathCstr;
_baton->base_path_len = strlen(_basePathCstr);
_baton->path_start = _pathStartCstr;
}
- (void)loadVcsIgnores {
const char *ignoreFile = NULL;
for (int i = 0; (ignore_pattern_files[i] != NULL); i++) {
ignoreFile = ignore_pattern_files[i];
char *dirFullPath = NULL;
ag_asprintf(
&dirFullPath,
"%s/%s",
[_url.path cStringUsingEncoding:NSUTF8StringEncoding],
ignoreFile
);
load_ignore_patterns(_ig, dirFullPath);
free(dirFullPath);
dirFullPath = NULL;
}
}
- (void)dealloc {
cleanup_ignore(_ig);
free(_baton);
free((void *) _basePathCstr);
free((void *) _pathStartCstr);
}
+ (instancetype)stubBatonWithGlobalGitignores {
static FileScanBaton *sharedStub = nil;
static dispatch_once_t singletonToken;
dispatch_once(&singletonToken, ^{
sharedStub = [[FileScanBaton alloc] initAsStub];
});
return sharedStub;
}
- (instancetype)initAsStub {
self = [super init];
if (self == nil) {return nil;}
_baseUrl = [NSURL fileURLWithPath:@"~"];
_url = _baseUrl;
_pathStart = @".";
_ig = init_ignore(NULL, "", 0);
[self initScanDirBaton];
load_global_gitignores(_ig);
return self;
}
static const char *cfstr_to_cstr_copy(CFStringRef cfstr) {
CFIndex out_len = 0;
CFRange whole_range = CFRangeMake(0, CFStringGetLength(cfstr));
CFIndex converted = CFStringGetBytes(
cfstr,
whole_range,
kCFStringEncodingUTF8,
0,
false,
NULL,
0,
&out_len
);
if (converted == 0 || out_len == 0) {return NULL;}
char *result = malloc((size_t) (out_len + 1));
converted = CFStringGetBytes(
cfstr,
whole_range,
kCFStringEncodingUTF8,
0,
false,
(UInt8 *) result,
out_len,
NULL
);
if (converted == 0) {
free(result);
return NULL;
}
result[out_len] = NULL;
return result;
}
// From the_silver_searcher/options.c
static void load_global_gitignores(ignores *ig) {
const char *home_dir = getenv("HOME");
FILE *gitconfig_file = NULL;
size_t buf_len = 0;
char *gitconfig_res = NULL;
gitconfig_file = popen("git config -z --path --get core.excludesfile 2>/dev/null", "r");
if (gitconfig_file != NULL) {
do {
gitconfig_res = ag_realloc(gitconfig_res, buf_len + 65);
buf_len += fread(gitconfig_res + buf_len, 1, 64, gitconfig_file);
} while (!feof(gitconfig_file) && buf_len > 0 && buf_len % 64 == 0);
gitconfig_res[buf_len] = '\0';
if (buf_len == 0) {
free(gitconfig_res);
const char *config_home = getenv("XDG_CONFIG_HOME");
if (config_home) {
ag_asprintf(&gitconfig_res, "%s/%s", config_home, "git/ignore");
} else {
ag_asprintf(&gitconfig_res, "%s/%s", home_dir, ".config/git/ignore");
}
}
log_debug("global core.excludesfile: %s", gitconfig_res);
load_ignore_patterns(ig, gitconfig_res);
free(gitconfig_res);
pclose(gitconfig_file);
}
}
@end

View File

@ -0,0 +1,13 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Foundation/Foundation.h>
@interface NSURL (Commons)
- (struct dirent)fakeDirent;
- (uint8_t)direntType;
@end

View File

@ -0,0 +1,40 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import "FoundationCommons.h"
#import <dirent.h>
@implementation NSURL (Commons)
- (struct dirent)fakeDirent {
const char *nameCstr = [self.lastPathComponent cStringUsingEncoding:NSUTF8StringEncoding];
struct dirent result = {
.d_type=self.direntType,
.d_namlen=(__uint16_t) strlen(nameCstr),
};
strcpy(result.d_name, nameCstr);
return result;
}
- (uint8_t)direntType {
NSString *value = nil;
if (![self getResourceValue:&value forKey:NSURLFileResourceTypeKey error:nil]) {
return DT_UNKNOWN;
}
if ([value isEqualToString:NSURLFileResourceTypeNamedPipe]) {return DT_FIFO;}
if ([value isEqualToString:NSURLFileResourceTypeCharacterSpecial]) {return DT_CHR;}
if ([value isEqualToString:NSURLFileResourceTypeDirectory]) {return DT_DIR;}
if ([value isEqualToString:NSURLFileResourceTypeBlockSpecial]) {return DT_BLK;}
if ([value isEqualToString:NSURLFileResourceTypeRegular]) {return DT_REG;}
if ([value isEqualToString:NSURLFileResourceTypeSymbolicLink]) {return DT_LNK;}
if ([value isEqualToString:NSURLFileResourceTypeSocket]) {return DT_SOCK;}
return DT_UNKNOWN;
}
@end

View File

@ -8,6 +8,8 @@ import os
extension URL {
var direntType: UInt8 { (self as NSURL).direntType() }
func isDirectParent(of url: URL) -> Bool {
guard self.isFileURL && url.isFileURL else {
return false

View File

@ -0,0 +1,18 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import <Foundation/Foundation.h>
@interface FuzzyMatcher : NSObject
+ (NSInteger)maxPatternLength;
+ (NSInteger)maxTextLength;
+ (NSInteger)minScore;
- (instancetype _Nonnull)initWithPattern:(NSString * _Nonnull)pattern;
- (NSInteger)score:(NSString * _Nonnull)text;
@end

View File

@ -0,0 +1,33 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
#import "FuzzyMatcher.h"
#import "fuzzy_match.hh"
@implementation FuzzyMatcher {
ccls::FuzzyMatcher *_matcher;
}
+ (NSInteger)maxPatternLength {return ccls::FuzzyMatcher::kMaxPat;}
+ (NSInteger)maxTextLength {return ccls::FuzzyMatcher::kMaxText;}
+ (NSInteger)minScore {return ccls::FuzzyMatcher::kMinScore;}
- (instancetype)initWithPattern:(NSString *)pattern {
self = [super init];
if (!self) {return nil;}
_matcher = new ccls::FuzzyMatcher([pattern cStringUsingEncoding:NSUTF8StringEncoding], 0);
return self;
}
- (NSInteger)score:(NSString *)text {
return _matcher->match([text cStringUsingEncoding:NSUTF8StringEncoding], false);
}
@end

View File

@ -0,0 +1,58 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import os
class FuzzyMatcherPool {
let pattern: String
init(pattern: String, initialPoolSize: Int = 2) {
self.pattern = pattern
self.matchers = []
for _ in 0..<initialPoolSize {
self.matchers.append(FuzzyMatcher(pattern: pattern))
}
}
func request() -> FuzzyMatcher {
return self.lock.withLock {
if self.matchers.isEmpty {
let matcher = FuzzyMatcher(pattern: self.pattern)
return matcher
}
let matcher = self.matchers.popLast()! // We know that the array is not empty!
return matcher
}
}
func giveBack(_ matcher: FuzzyMatcher) {
self.lock.withLock {
self.matchers.append(matcher)
}
}
deinit {
self.log.debug(
"DEBUG FuzzyMatcherPool with pattern '\(self.pattern)' had \(self.matchers.count) matchers."
)
}
private var matchers: [FuzzyMatcher]
private let lock = NSLock()
private let log = OSLog(subsystem: Defs.loggerSubsystem, category: Defs.LoggerCategory.service)
}
private extension NSLocking {
func withLock<T>(_ body: () -> T) -> T {
self.lock()
defer { self.unlock() }
return body()
}
}

View File

@ -0,0 +1,191 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "fuzzy_match.hh"
#include <algorithm>
#include <ctype.h>
#include <stdio.h>
#include <vector>
namespace ccls {
namespace {
enum CharClass { Other, Lower, Upper };
enum CharRole { None, Tail, Head };
CharClass getCharClass(int c) {
if (islower(c))
return Lower;
if (isupper(c))
return Upper;
return Other;
}
void calculateRoles(std::string_view s, int roles[], int *class_set) {
if (s.empty()) {
*class_set = 0;
return;
}
CharClass pre = Other, cur = getCharClass(s[0]), suc;
*class_set = 1 << cur;
auto fn = [&]() {
if (cur == Other)
return None;
// U(U)L is Head while U(U)U is Tail
return pre == Other || (cur == Upper && (pre == Lower || suc == Lower))
? Head
: Tail;
};
for (size_t i = 0; i < s.size() - 1; i++) {
suc = getCharClass(s[i + 1]);
*class_set |= 1 << suc;
roles[i] = fn();
pre = cur;
cur = suc;
}
roles[s.size() - 1] = fn();
}
} // namespace
int FuzzyMatcher::missScore(int j, bool last) {
int s = -3;
if (last)
s -= 10;
if (text_role[j] == Head)
s -= 10;
return s;
}
int FuzzyMatcher::matchScore(int i, int j, bool last) {
int s = 0;
// Case matching.
if (pat[i] == text[j]) {
s++;
// pat contains uppercase letters or prefix matching.
if ((pat_set & 1 << Upper) || i == j)
s++;
}
if (pat_role[i] == Head) {
if (text_role[j] == Head)
s += 30;
else if (text_role[j] == Tail)
s -= 10;
}
// Matching a tail while previous char wasn't matched.
if (text_role[j] == Tail && i && !last)
s -= 30;
// First char of pat matches a tail.
if (i == 0 && text_role[j] == Tail)
s -= 40;
return s;
}
FuzzyMatcher::FuzzyMatcher(std::string_view pattern, int sensitivity) {
calculateRoles(pattern, pat_role, &pat_set);
if (sensitivity == 1)
sensitivity = pat_set & 1 << Upper ? 2 : 0;
case_sensitivity = sensitivity;
size_t n = 0;
for (size_t i = 0; i < pattern.size(); i++)
if (pattern[i] != ' ') {
pat += pattern[i];
low_pat[n] = (char)::tolower(pattern[i]);
pat_role[n] = pat_role[i];
n++;
}
}
int FuzzyMatcher::match(std::string_view text, bool strict) {
if (pat.empty() != text.empty())
return kMinScore;
int n = int(text.size());
if (n > kMaxText)
return kMinScore + 1;
this->text = text;
for (int i = 0; i < n; i++)
low_text[i] = (char)::tolower(text[i]);
calculateRoles(text, text_role, &text_set);
if (strict && n && !!pat_role[0] != !!text_role[0])
return kMinScore;
dp[0][0][0] = dp[0][0][1] = 0;
for (int j = 0; j < n; j++) {
dp[0][j + 1][0] = dp[0][j][0] + missScore(j, false);
dp[0][j + 1][1] = kMinScore * 2;
}
for (int i = 0; i < int(pat.size()); i++) {
int(*pre)[2] = dp[i & 1];
int(*cur)[2] = dp[(i + 1) & 1];
cur[i][0] = cur[i][1] = kMinScore;
for (int j = i; j < n; j++) {
cur[j + 1][0] = std::max(cur[j][0] + missScore(j, false),
cur[j][1] + missScore(j, true));
// For the first char of pattern, apply extra restriction to filter bad
// candidates (e.g. |int| in |PRINT|)
cur[j + 1][1] = (case_sensitivity ? pat[i] == text[j]
: low_pat[i] == low_text[j] &&
(i || text_role[j] != Tail ||
pat[i] == text[j]))
? std::max(pre[j][0] + matchScore(i, j, false),
pre[j][1] + matchScore(i, j, true))
: kMinScore * 2;
}
}
// Enumerate the end position of the match in str. Each removed trailing
// character has a penulty.
int ret = kMinScore;
for (int j = pat.size(); j <= n; j++)
ret = std::max(ret, dp[pat.size() & 1][j][1] - 2 * (n - j));
return ret;
}
} // namespace ccls
#if 0
TEST_SUITE("fuzzy_match") {
bool Ranks(std::string_view pat, std::vector<const char*> texts) {
FuzzyMatcher fuzzy(pat, 0);
std::vector<int> scores;
for (auto text : texts)
scores.push_back(fuzzy.Match(text));
bool ret = true;
for (size_t i = 0; i < texts.size() - 1; i++)
if (scores[i] < scores[i + 1]) {
ret = false;
break;
}
if (!ret) {
for (size_t i = 0; i < texts.size(); i++)
printf("%s %d ", texts[i], scores[i]);
puts("");
}
return ret;
}
TEST_CASE("test") {
FuzzyMatcher fuzzy("", 0);
CHECK(fuzzy.Match("") == 0);
CHECK(fuzzy.Match("aaa") < 0);
// case
CHECK(Ranks("monad", {"monad", "Monad", "mONAD"}));
// initials
CHECK(Ranks("ab", {"ab", "aoo_boo", "acb"}));
CHECK(Ranks("CC", {"CamelCase", "camelCase", "camelcase"}));
CHECK(Ranks("cC", {"camelCase", "CamelCase", "camelcase"}));
CHECK(Ranks("c c", {"camelCase", "camel case", "CamelCase", "camelcase",
"camel ace"}));
CHECK(Ranks("Da.Te",
{"Data.Text", "Data.Text.Lazy", "Data.Aeson.Encoding.text"}));
CHECK(Ranks("foo bar.h", {"foo/bar.h", "foobar.h"}));
// prefix
CHECK(Ranks("is", {"isIEEE", "inSuf"}));
// shorter
CHECK(Ranks("ma", {"map", "many", "maximum"}));
CHECK(Ranks("print", {"printf", "sprintf"}));
// score(PRINT) = kMinScore
CHECK(Ranks("ast", {"ast", "AST", "INT_FAST16_MAX"}));
// score(PRINT) > kMinScore
CHECK(Ranks("Int", {"int", "INT", "PRINT"}));
}
}
#endif

View File

@ -0,0 +1,34 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <limits.h>
#include <string>
#include <string_view>
namespace ccls {
class FuzzyMatcher {
public:
constexpr static int kMaxPat = 100;
constexpr static int kMaxText = 200 + 300; // TAE: originally 200
// Negative but far from INT_MIN so that intermediate results are hard to
// overflow.
constexpr static int kMinScore = INT_MIN / 4;
FuzzyMatcher(std::string_view pattern, int case_sensitivity);
int match(std::string_view text, bool strict);
private:
int case_sensitivity;
std::string pat;
std::string_view text;
int pat_set, text_set;
char low_pat[kMaxPat], low_text[kMaxText];
int pat_role[kMaxPat], text_role[kMaxText];
int dp[2][kMaxText + 1][2];
int matchScore(int i, int j, bool last);
int missScore(int j, bool last);
};
} // namespace ccls

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="15702" systemVersion="19C57" minimumToolsVersion="Automatic" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<entity name="FileItem" representedClassName="FileItem" syncable="YES" codeGenerationType="class">
<attribute name="direntType" attributeType="Integer 16" usesScalarValueType="YES"/>
<attribute name="isHidden" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="isPackage" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="needsScanChildren" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="pathStart" attributeType="String"/>
<attribute name="url" attributeType="URI"/>
<relationship name="children" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="FileItem" inverseName="parent" inverseEntity="FileItem"/>
<relationship name="parent" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FileItem" inverseName="children" inverseEntity="FileItem"/>
<fetchIndex name="byIsDirAndUrlIndex">
<fetchIndexElement property="direntType" type="Binary" order="ascending"/>
<fetchIndexElement property="url" type="Binary" order="ascending"/>
</fetchIndex>
<fetchIndex name="byIsDirAndNeedsScanChildrenIndex">
<fetchIndexElement property="direntType" type="Binary" order="ascending"/>
<fetchIndexElement property="needsScanChildren" type="Binary" order="ascending"/>
</fetchIndex>
</entity>
<elements>
<element name="FileItem" positionX="-63" positionY="-18" width="128" height="163"/>
</elements>
</model>

View File

@ -0,0 +1,49 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import os
class FuzzySearchFileMonitor {
static let fileSystemEventsLatency = 1.0
func start(eventHandler: (@escaping (URL) -> Void)) throws {
self.monitor = try EonilFSEventStream(
pathsToWatch: [urlToMonitor.path],
sinceWhen: EonilFSEventsEventID.getCurrentEventId(),
latency: FuzzySearchFileMonitor.fileSystemEventsLatency,
flags: [],
handler: { [weak self] event in
if event.flag == .historyDone {
self?.log.info("Not firing first event (.historyDone): \(event)")
return
}
eventHandler(URL(fileURLWithPath: event.path))
}
)
self.monitor?.setDispatchQueue(globalFileMonitorQueue)
try self.monitor?.start()
self.log.info("Started monitoring \(self.urlToMonitor)")
}
init(urlToMonitor: URL) {
self.urlToMonitor = urlToMonitor
}
deinit {
self.monitor?.stop()
self.monitor?.invalidate()
}
private var urlToMonitor: URL
private var monitor: EonilFSEventStream?
private let log = OSLog(subsystem: Defs.loggerSubsystem, category: Defs.LoggerCategory.service)
}
private let globalFileMonitorQueue = DispatchQueue.global(qos: .userInitiated)

View File

@ -0,0 +1,457 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import CoreData
import os
class FuzzySearchService {
typealias ScoredUrlsCallback = ([ScoredUrl]) -> Void
var root: URL {
didSet {
self.queue.sync {
self.deleteAllFiles()
self.ensureRootFileInStore()
}
}
}
var usesVcsIgnores = true {
willSet { self.stopScanScore() }
didSet {
self.queue.sync {
self.deleteAllFiles()
self.ensureRootFileInStore()
}
}
}
let coreDataStack: CoreDataStack
func cleanUp() {
do {
try self.coreDataStack.deleteStore()
} catch {
self.log.error("Could not delete core data store: \(error)")
}
}
func stopScanScore() {
self.stopLock.lock()
defer { self.stopLock.unlock() }
self.stop = true
}
func scanScore(
for pattern: String,
beginCallback: @escaping () -> Void,
endCallback: @escaping () -> Void,
callback: @escaping ScoredUrlsCallback
) {
self.queue.async {
self.log.info("Starting fuzzy search for \(pattern) in \(self.root)")
beginCallback()
defer { endCallback() }
let ctx = self.writeContext
ctx.performAndWait {
self.stopLock.lock()
self.stop = false
self.stopLock.unlock()
let matcherPool = FuzzyMatcherPool(pattern: pattern, initialPoolSize: 2)
self.scanScoreSavedFiles(matcherPool: matcherPool, context: ctx, callback: callback)
if self.shouldStop() { return }
self.scanScoreFilesNeedScanning(matcherPool: matcherPool, context: ctx, callback: callback)
}
self.log.info("Finished fuzzy search for \(pattern) in \(self.root)")
}
}
private func scanScoreSavedFiles(
matcherPool: FuzzyMatcherPool,
context: NSManagedObjectContext,
callback: ScoredUrlsCallback
) {
let predicate = NSPredicate(format: "direntType != %d", DT_DIR)
let countReq = FileItem.fetchRequest()
countReq.predicate = predicate
countReq.includesSubentities = false
guard let count = try? context.count(for: countReq) else {
self.log.error("Could not get count of Files")
return
}
self.log.info("Scoring \(count) Files for pattern \(matcherPool.pattern)")
let urlSorter = NSSortDescriptor(key: "url", ascending: true)
let fetchReq = FileItem.fetchRequest()
fetchReq.fetchLimit = coreDataBatchSize
fetchReq.sortDescriptors = [urlSorter]
fetchReq.predicate = predicate
let chunkCount = Int(ceil(Double(count) / Double(coreDataBatchSize)))
for chunkIndex in (0..<chunkCount) {
if self.shouldStop({ context.reset() }) { return }
let start = Swift.min(chunkIndex * coreDataBatchSize, count)
fetchReq.fetchOffset = start
do {
self.scoreFiles(
matcherPool: matcherPool,
files: try context.fetch(fetchReq),
callback: callback
)
} catch {
self.log.error("Could not fetch \(fetchReq): \(error)")
}
context.reset()
}
}
private func scanScoreFilesNeedScanning(
matcherPool: FuzzyMatcherPool,
context: NSManagedObjectContext,
callback: ([ScoredUrl]) -> ()
) {
let req = self.fileFetchRequest("needsScanChildren == TRUE AND direntType == %d", [DT_DIR])
do {
let foldersToScan = try context.fetch(req)
// We use the ID of objects since we reset in scanScore(), which resets all properties of
// foldersToScan after first folderToScan.
foldersToScan.forEach { folder in
self.scanScore(
matcherPool: matcherPool,
folderId: folder.objectID,
context: context,
callback: callback
)
}
} catch {
self.log.error("Could not fetch \(req): \(error)")
}
}
private func scanScore(
matcherPool: FuzzyMatcherPool,
folderId: NSManagedObjectID,
context: NSManagedObjectContext,
callback: ([ScoredUrl]) -> ()
) {
var saveCounter = 1
var counter = 1
guard let folder = context.object(with: folderId) as? FileItem else {
self.log.error("Could not convert object with ID \(folderId) to File")
return
}
let (initialBaton, initialBatons) = self.baton(for: folder.url!)
let testIgnores = self.usesVcsIgnores
var batons = initialBatons
var stack = [(initialBaton, folder)]
while let iterElement = stack.popLast() {
if self.shouldStop({ self.saveAndReset(context: context) }) { return }
autoreleasepool {
let baton = iterElement.0
let folder = iterElement.1
let urlToScan = folder.url!
let childUrls = FileUtils
.directDescendants(of: urlToScan)
.filter {
let keep = testIgnores ? baton.test($0) : true
if !keep { self.log.debug("Ignoring \($0.path)") }
return keep
}
let childFiles = childUrls
.filter { !$0.isPackage }
.map { url -> FileItem in self.file(fromUrl: url, pathStart: baton.pathStart, in: context) }
saveCounter += childFiles.count
counter += childFiles.count
folder.addChildren(Set(childFiles))
folder.needsScanChildren = false
let childFolders = childFiles.filter { $0.direntType == DT_DIR }
let childBatons = childFolders.map { FileScanBaton(parent: baton, url: $0.url!) }
batons.append(contentsOf: childBatons)
stack.append(contentsOf: zip(childBatons, childFolders))
if saveCounter > coreDataBatchSize {
self.log.debug(
"Flushing and scoring \(saveCounter) Files, stack has \(stack.count) Files"
)
self.scoreAllRegisteredFiles(
matcherPool: matcherPool,
context: context,
callback: callback
)
self.saveAndReset(context: context)
saveCounter = 0
// We have to re-fetch the Files in stack to get the parent-children relationship right.
// Since objectID survives NSManagedObjectContext.reset(), we can re-populate (re-fetch)
// stack using the objectIDs.
let ids = stack.map { $0.1.objectID }
stack = Array(zip(
stack.map { $0.0 },
ids.map { context.object(with: $0) as! FileItem }
))
}
}
}
self.log.debug("Flushing and scoring last \(saveCounter) Files")
self.scoreAllRegisteredFiles(matcherPool: matcherPool, context: context, callback: callback)
self.saveAndReset(context: context)
self.log.debug("Stored \(counter) Files")
}
private func saveAndReset(context: NSManagedObjectContext) {
do {
try context.save()
} catch {
self.log.error("There was an error saving the context: \(error)")
}
context.reset()
}
private func shouldStop(_ body: (() -> Void)? = nil) -> Bool {
self.stopLock.lock()
defer { self.stopLock.unlock() }
if self.stop {
body?()
return true
}
return false
}
private func scoreAllRegisteredFiles(
matcherPool: FuzzyMatcherPool,
context: NSManagedObjectContext,
callback: ([ScoredUrl]) -> ()
) {
let files = context.registeredObjects
.compactMap { $0 as? FileItem }
.filter { $0.direntType != DT_DIR }
self.log.debug("Scoring \(files.count) Files")
self.scoreFiles(matcherPool: matcherPool, files: files, callback: callback)
}
private func scoreFiles(
matcherPool: FuzzyMatcherPool,
files: [FileItem],
callback: ScoredUrlsCallback
) {
let matchFullPath = matcherPool.pattern.contains("/")
let count = files.count
let chunkCount = Int(ceil(Double(count) / Double(fuzzyMatchChunkSize)))
DispatchQueue.concurrentPerform(iterations: chunkCount) { chunkIndex in
let matcher = matcherPool.request()
defer { matcherPool.giveBack(matcher) }
let start = Swift.min(chunkIndex * fuzzyMatchChunkSize, count)
let end = Swift.min(start + fuzzyMatchChunkSize, count)
if self.shouldStop() { return }
let scoreThreshold = FuzzyMatcher.minScore() + 1
callback(files[start..<end].compactMap { file in
let url = file.url!
let score = matcher.score(matchFullPath ? url.path : url.lastPathComponent)
if score <= scoreThreshold { return nil }
return ScoredUrl(url: url, score: score)
})
}
}
init(root: URL) throws {
self.coreDataStack = try CoreDataStack(
modelName: "FuzzySearch",
storeLocation: .temp(UUID().uuidString),
deleteOnDeinit: true
)
self.root = root
self.writeContext = self.coreDataStack.newBackgroundContext()
self.fileMonitor = FuzzySearchFileMonitor(urlToMonitor: root)
self.queue.sync { self.ensureRootFileInStore() }
try self.fileMonitor.start { [weak self] url in self?.handleChange(in: url) }
}
private func ensureRootFileInStore() {
self.queue.async {
let ctx = self.writeContext
ctx.performAndWait {
let req = self.fileFetchRequest("url == %@", [self.root])
do {
let files = try ctx.fetch(req)
guard files.isEmpty else { return }
_ = self.file(fromUrl: self.root, pathStart: ".", in: ctx)
try ctx.save()
} catch {
self.log.error("Could not ensure root File in Core Data: \(error)")
}
}
}
}
private func handleChange(in folderUrl: URL) {
self.log.debug("File event in \(folderUrl)")
self.queue.async {
let ctx = self.writeContext
ctx.performAndWait {
let req = self.fileFetchRequest("url == %@", [folderUrl])
do {
let fetchResult = try ctx.fetch(req)
guard let folder = fetchResult.first else {
self.log.debug("File with url \(folderUrl) not found, doing nothing")
return
}
for child in folder.children ?? [] { ctx.delete(child) }
folder.needsScanChildren = true
self.log.debug("Marked \(folder.url!) for scanning")
try ctx.save()
} catch {
self.log.error(
"Could not fetch File with url \(folderUrl) "
+ "or could not save after setting needsScanChildren: \(error)"
)
}
ctx.reset()
}
}
}
private func fileFetchRequest(
_ format: String,
_ arguments: [Any]? = nil
) -> NSFetchRequest<FileItem> {
let req: NSFetchRequest<FileItem> = FileItem.fetchRequest()
req.predicate = NSPredicate(format: format, argumentArray: arguments)
return req
}
/// Call this in self.queue.(a)sync
private func deleteAllFiles() {
let delReq = NSBatchDeleteRequest(
fetchRequest: NSFetchRequest(entityName: String(describing: FileItem.self))
)
let ctx = self.writeContext
ctx.performAndWait {
do {
try ctx.execute(delReq)
} catch {
self.log.error("Could not delete all Files: \(error)")
}
}
}
private func baton(for url: URL) -> (FileScanBaton, [FileScanBaton]) {
assert(self.root.isParent(of: url) || url == self.root)
if url == self.root {
let rootBaton = FileScanBaton(baseUrl: self.root)
return (rootBaton, [rootBaton])
}
let rootBaton = FileScanBaton(baseUrl: self.root)
var batons = [rootBaton]
var pathComps = url.pathComponents.suffix(from: self.root.pathComponents.count)
var lastBaton = rootBaton
var lastUrl = self.root
while let pathComp = pathComps.popFirst() {
let childUrl = lastUrl.appendingPathComponent(pathComp)
let childBaton = FileScanBaton(
parent: lastBaton,
url: childUrl
)
batons.append(childBaton)
lastBaton = childBaton
lastUrl = childUrl
}
return (lastBaton, batons)
}
private func file(
fromUrl url: URL,
pathStart: String,
in context: NSManagedObjectContext
) -> FileItem {
let file = FileItem(context: context)
file.url = url
file.direntType = Int16(url.direntType)
file.isHidden = url.isHidden
file.isPackage = url.isPackage
file.pathStart = pathStart
if url.isDir { file.needsScanChildren = true }
return file
}
func debug() {
let req = self.fileFetchRequest("needsScanChildren == TRUE AND direntType == %d", [DT_DIR]);
self.queue.async {
let moc = self.writeContext
moc.performAndWait {
do {
let result = try moc.fetch(req)
Swift.print("Files with needsScanChildren = true:")
result.forEach {
Swift.print("\t\($0.url)")
}
Swift.print("--- \(result.count)")
} catch {
Swift.print(error)
}
}
}
}
private var stop = false
private let stopLock = NSLock()
private let queue = DispatchQueue(label: "scan-score-queue", qos: .userInitiated)
private let fileMonitor: FuzzySearchFileMonitor
private let writeContext: NSManagedObjectContext
private let log = OSLog(subsystem: Defs.loggerSubsystem, category: Defs.LoggerCategory.service)
}
private let fuzzyMatchChunkSize = 100
private let coreDataBatchSize = 10000

View File

@ -16,7 +16,7 @@ class GeneralPref: PrefPane, UiComponent, NSTextFieldDelegate {
case setOpenOnLaunch(Bool)
case setAfterLastWindowAction(AppState.AfterLastWindowAction)
case setOpenOnReactivation(Bool)
case setIgnorePatterns(Set<FileItemIgnorePattern>)
case setDefaultUsesVcsIgnores(Bool)
}
override var displayName: String {
@ -27,10 +27,6 @@ class GeneralPref: PrefPane, UiComponent, NSTextFieldDelegate {
return true
}
override func windowWillClose() {
self.ignorePatternsAction()
}
required init(source: Observable<StateType>, emitter: ActionEmitter, state: StateType) {
self.emit = emitter.typedEmit()
@ -40,13 +36,11 @@ class GeneralPref: PrefPane, UiComponent, NSTextFieldDelegate {
self.openWhenLaunchingCheckbox.boolState = state.openNewMainWindowOnLaunch
self.openOnReactivationCheckbox.boolState = state.openNewMainWindowOnReactivation
self.defaultUsesVcsIgnoresCheckbox.boolState = state.openQuickly.defaultUsesVcsIgnores
self.lastWindowAction = state.afterLastWindowAction
self.afterLastWindowPopup.selectItem(at: indexToAfterLastWindowAction.firstIndex(of: state.afterLastWindowAction) ?? 0)
self.ignorePatterns = state.openQuickly.ignorePatterns
self.ignoreField.stringValue = FileItemIgnorePattern.toString(state.openQuickly.ignorePatterns)
source
.observeOn(MainScheduler.instance)
.subscribe(onNext: { state in
@ -75,13 +69,10 @@ class GeneralPref: PrefPane, UiComponent, NSTextFieldDelegate {
private let openWhenLaunchingCheckbox = NSButton(forAutoLayout: ())
private let openOnReactivationCheckbox = NSButton(forAutoLayout: ())
private let defaultUsesVcsIgnoresCheckbox = NSButton(forAutoLayout: ())
private let afterLastWindowPopup = NSPopUpButton(forAutoLayout: ())
private let ignoreField = NSTextField(forAutoLayout: ())
private var ignorePatterns = Set<FileItemIgnorePattern>()
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@ -92,10 +83,13 @@ class GeneralPref: PrefPane, UiComponent, NSTextFieldDelegate {
let openUntitledWindowTitle = self.titleTextField(title: "Open Untitled Window:")
self.configureCheckbox(button: self.openWhenLaunchingCheckbox,
title: "On launch",
action: #selector(GeneralPref.openUntitledWindowWhenLaunchingAction(_:)))
action: #selector(GeneralPref.openUntitledWindowWhenLaunchingAction))
self.configureCheckbox(button: self.openOnReactivationCheckbox,
title: "On re-activation",
action: #selector(GeneralPref.openUntitledWindowOnReactivationAction(_:)))
action: #selector(GeneralPref.openUntitledWindowOnReactivationAction))
self.configureCheckbox(button: self.defaultUsesVcsIgnoresCheckbox,
title: "Use VCS Ignores",
action: #selector(GeneralPref.defaultUsesVcsIgnoresAction))
let whenLaunching = self.openWhenLaunchingCheckbox
let onReactivation = self.openOnReactivationCheckbox
@ -110,19 +104,17 @@ class GeneralPref: PrefPane, UiComponent, NSTextFieldDelegate {
"Quit",
])
let ignoreListTitle = self.titleTextField(title: "Files To Ignore:")
let ignoreField = self.ignoreField
NotificationCenter.default.addObserver(forName: NSControl.textDidEndEditingNotification,
object: ignoreField,
queue: nil) { [unowned self] _ in
self.ignorePatternsAction()
}
let ignoreListTitle = self.titleTextField(title: "Open Quickly:")
let ignoreInfo =
self.infoTextField(markdown:
"Comma-separated list of ignore patterns \n"
+ "Matching files will be ignored in \"Open Quickly\" and the file browser. \n"
+ "Example: `*/.git, */node_modules` \n"
+ "For detailed information see [VimR Wiki](https://github.com/qvacua/vimr/wiki)."
self.infoTextField(
markdown:
"""
When checked, the ignore files of VCSs, e.g. `gitignore`, will we used to ignore files.
This checkbox will set the initial value for each VimR window.
You can change this setting for each VimR window in the Open Quickly window.
The behavior should be almost identical to that of
[The Silver Searcher](https://github.com/ggreer/the_silver_searcher).
"""
)
let cliToolTitle = self.titleTextField(title: "CLI Tool:")
@ -137,13 +129,15 @@ class GeneralPref: PrefPane, UiComponent, NSTextFieldDelegate {
markdown: "Put the executable `vimr` in your `$PATH` and execute `vimr -h` for help."
)
let vcsIg = self.defaultUsesVcsIgnoresCheckbox
self.addSubview(paneTitle)
self.addSubview(openUntitledWindowTitle)
self.addSubview(whenLaunching)
self.addSubview(onReactivation)
self.addSubview(vcsIg)
self.addSubview(ignoreListTitle)
self.addSubview(ignoreField)
self.addSubview(ignoreInfo)
self.addSubview(afterLastWindowTitle)
@ -175,17 +169,16 @@ class GeneralPref: PrefPane, UiComponent, NSTextFieldDelegate {
lastWindow.autoPinEdge(.top, to: .bottom, of: onReactivation, withOffset: 18)
lastWindow.autoPinEdge(.left, to: .right, of: afterLastWindowTitle, withOffset: 5)
ignoreListTitle.autoAlignAxis(.baseline, toSameAxisOf: ignoreField)
ignoreListTitle.autoAlignAxis(.baseline, toSameAxisOf: vcsIg)
ignoreListTitle.autoPinEdge(.right, to: .right, of: openUntitledWindowTitle)
ignoreListTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
ignoreField.autoPinEdge(.top, to: .bottom, of: lastWindow, withOffset: 18)
ignoreField.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
ignoreField.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
vcsIg.autoPinEdge(.top, to: .bottom, of: lastWindow, withOffset: 18)
vcsIg.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
ignoreInfo.autoPinEdge(.top, to: .bottom, of: ignoreField, withOffset: 5)
ignoreInfo.autoPinEdge(.top, to: .bottom, of: vcsIg, withOffset: 5)
ignoreInfo.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
ignoreInfo.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
ignoreInfo.autoPinEdge(.left, to: .left, of: vcsIg)
cliToolTitle.autoAlignAxis(.baseline, toSameAxisOf: cliToolButton)
cliToolTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
@ -234,6 +227,10 @@ extension GeneralPref {
}
}
@objc func defaultUsesVcsIgnoresAction(_ sender: NSButton) {
self.emit(.setDefaultUsesVcsIgnores(sender.boolState))
}
@objc func openUntitledWindowWhenLaunchingAction(_ sender: NSButton) {
self.emit(.setOpenOnLaunch(self.openWhenLaunchingCheckbox.boolState))
}
@ -253,16 +250,6 @@ extension GeneralPref {
self.emit(.setAfterLastWindowAction(self.lastWindowAction))
}
private func ignorePatternsAction() {
let patterns = FileItemIgnorePattern.from(string: self.ignoreField.stringValue)
if patterns == self.ignorePatterns {
return
}
self.ignorePatterns = patterns
self.emit(.setIgnorePatterns(ignorePatterns))
}
private func alert(title: String, info: String) {
let alert = NSAlert()
alert.alertStyle = .warning

View File

@ -24,9 +24,8 @@ class GeneralPrefReducer: ReducerType {
case let .setOpenOnReactivation(value):
state.openNewMainWindowOnReactivation = value
case let .setIgnorePatterns(patterns):
state.openQuickly.ignorePatterns = patterns
state.openQuickly.ignoreToken = Token()
case let .setDefaultUsesVcsIgnores(value):
state.openQuickly.defaultUsesVcsIgnores = value
}

View File

@ -1224,7 +1224,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>SNAPSHOT-330</string>
<string>SNAPSHOT-331</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
@ -1241,7 +1241,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>330</string>
<string>331</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.productivity</string>
<key>LSMinimumSystemVersion</key>

View File

@ -151,6 +151,14 @@ extension MainWindow {
}
func windowShouldClose(_: NSWindow) -> Bool {
if (self.neoVimView.isBlocked().syncValue() ?? false) {
let alert = NSAlert()
alert.messageText = "Nvim is waiting for your input."
alert.alertStyle = .informational
alert.runModal()
return false
}
guard (self.neoVimView.isCurrentBufferDirty().syncValue() ?? false) else {
try? self.neoVimView.closeCurrentTab().wait()
return false

View File

@ -23,9 +23,7 @@ class MainWindow: NSObject,
let emit: (UuidAction<Action>) -> Void
let windowController: NSWindowController
var window: NSWindow {
return self.windowController.window!
}
var window: NSWindow { self.windowController.window! }
let workspace: Workspace
let neoVimView: NvimView
@ -504,11 +502,11 @@ class MainWindow: NSObject,
private func showInitError() {
let notification = NSUserNotification()
notification.title = "Error during initialization"
notification
.informativeText = """
There was an error during the initialization of NeoVim.
Use :messages to view the error messages.
"""
notification.informativeText =
"""
There was an error during the initialization of NeoVim.
Use :messages to view the error messages.
"""
NSUserNotificationCenter.default.deliver(notification)
}

View File

@ -1,125 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
class Matcher {
static let uppercaseCharSet = CharacterSet.uppercaseLetters
enum ExactMatchResult {
case none
case exact
case prefix
case suffix
case contains
}
static func exactMatchIgnoringCase(_ target: String, pattern: String) -> ExactMatchResult {
let ltarget = target.lowercased()
let lpattern = pattern.lowercased()
if ltarget == lpattern {
return .exact
}
if ltarget.hasPrefix(lpattern) {
return .prefix
}
if ltarget.hasSuffix(lpattern) {
return .suffix
}
if ltarget.contains(lpattern) {
return .contains
}
return .none
}
static func numberOfUppercaseMatches(_ target: String, pattern: String) -> Int {
var tscalars = target.unicodeScalars.filter { self.uppercaseCharSet.contains($0) }
let count = tscalars.count
guard count > 0 else {
return 0
}
let pscalars = pattern.uppercased().unicodeScalars
pscalars.forEach {
if let idx = tscalars.firstIndex(of: $0) {
tscalars.remove(at: idx)
}
}
return count - tscalars.count
}
/// Matches `pattern` to `target` in a fuzzy way.
/// - returns: number of matched characters where first character match gets a bonus of 5
static func fuzzyIgnoringCase(_ target: String, pattern: String) -> Int {
let tlower = target.lowercased()
let plower = pattern.lowercased()
let tchars = tlower.unicodeScalars
let pchars = plower.unicodeScalars
var result = 0
var pidx = pchars.startIndex
for tchar in tchars {
if pchars[pidx] == tchar {
result += 1
pidx = pchars.index(after: pidx)
if pidx == pchars.endIndex {
break
}
}
}
if tchars.first == pchars.first {
result += 5
}
return result
}
/// 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(repeating: 0, count: m &+ 1)
var curRow = Array(repeating: 0, count: m &+ 1)
for i in 0 ... m {
prevRow[i] = i
}
for (j, tchar) in t.enumerated() {
curRow[0] = j &+ 1
for (i, schar) in s.enumerated() {
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]
}
}

View File

@ -1,115 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
class OpenQuicklyFilterOperation: Operation {
init(forOpenQuickly openQuickly: OpenQuicklyWindow) {
self.openQuickly = openQuickly
self.pattern = openQuickly.pattern
self.cwd = openQuickly.cwd
self.flatFileItems = openQuickly.flatFileItems
super.init()
}
override func main() {
self.openQuickly.scanCondition.lock()
self.openQuickly.pauseScan = true
defer {
self.openQuickly.pauseScan = false
self.openQuickly.scanCondition.broadcast()
self.openQuickly.scanCondition.unlock()
}
if self.isCancelled {
return
}
if self.flatFileItems.isEmpty {
return
}
let sorted: [ScoredFileItem]
if pattern.count == 0 {
let truncatedItems = self.flatFileItems[0...min(maxResultCount, self.flatFileItems.count - 1)]
sorted = truncatedItems.map { ScoredFileItem(score: 0, url: $0.url) }
} else {
DispatchQueue.main.async { self.openQuickly.startProgress() }
defer { DispatchQueue.main.async { self.openQuickly.endProgress() } }
let count = self.flatFileItems.count
let chunksCount = Int(ceil(Float(count) / Float(chunkSize)))
let useFullPath = pattern.contains("/")
let cwdPath = self.cwd.path + "/"
var result = [ScoredFileItem]()
var spinLock = OS_SPINLOCK_INIT
let cleanedPattern = useFullPath ? self.pattern.replacingOccurrences(of: "/", with: "")
: self.pattern
DispatchQueue.concurrentPerform(iterations: chunksCount) { [unowned self] idx in
if self.isCancelled {
return
}
let startIndex = min(idx * chunkSize, count)
let endIndex = min(startIndex + chunkSize, count)
let chunkedItems = self.flatFileItems[startIndex..<endIndex]
let chunkedResult: [ScoredFileItem] = chunkedItems.compactMap {
if self.isCancelled {
return nil
}
let url = $0.url
if useFullPath {
let target = url.path.replacingOccurrences(of: cwdPath, with: "")
.replacingOccurrences(of: "/", with: "")
return ScoredFileItem(score: Scorer.score(target, pattern: cleanedPattern), url: url)
}
return ScoredFileItem(score: Scorer.score(url.lastPathComponent, pattern: cleanedPattern), url: url)
}
if self.isCancelled {
return
}
OSSpinLockLock(&spinLock)
result.append(contentsOf: chunkedResult)
OSSpinLockUnlock(&spinLock)
}
if self.isCancelled {
return
}
sorted = result.sorted(by: >)
}
if self.isCancelled {
return
}
DispatchQueue.main.async {
let result = Array(sorted[0...min(maxResultCount, sorted.count - 1)])
self.openQuickly.reloadFileView(withScoredItems: result)
}
}
private let pattern: String
private let flatFileItems: [FileItem]
private let cwd: URL
private unowned let openQuickly: OpenQuicklyWindow
}
private let chunkSize = 100
private let maxResultCount = 500

View File

@ -16,20 +16,19 @@ class OpenQuicklyReducer: ReducerType {
func typedReduce(_ pair: ReduceTuple) -> ReduceTuple {
var appState = pair.state
appState.openQuickly.open = false
appState.openQuickly.flatFileItems = Observable.empty()
appState.openQuickly.cwd = FileUtils.userHomeUrl
switch pair.action {
case let .open(url):
guard let uuid = appState.currentMainWindowUuid else {
return pair
}
case let .setUsesVcsIgnores(usesVcsIgnores):
guard let uuid = appState.currentMainWindowUuid else { return pair }
appState.mainWindows[uuid]?.usesVcsIgnores = usesVcsIgnores
case let .open(url):
guard let uuid = appState.currentMainWindowUuid else { return pair }
appState.mainWindows[uuid]?.urlsToOpen[url] = .newTab
appState.openQuickly.open = false
case .close:
appState.openQuickly.open = false
break
}
@ -48,16 +47,10 @@ class OpenQuicklyReducer: ReducerType {
case .openQuickly:
var appState = pair.state
guard let uuid = appState.currentMainWindowUuid else {
return pair
}
guard let cwd = appState.mainWindows[uuid]?.cwd else {
return pair
}
guard let uuid = appState.currentMainWindowUuid,
appState.mainWindows[uuid]?.cwd != nil else { return pair }
appState.openQuickly.open = true
appState.openQuickly.cwd = cwd
return (appState, pair.action, true)

View File

@ -7,149 +7,221 @@ import Cocoa
import RxSwift
import RxCocoa
import PureLayout
import os
class OpenQuicklyWindow: NSObject,
UiComponent,
NSWindowDelegate,
NSTextFieldDelegate,
NSTableViewDelegate, NSTableViewDataSource {
NSTableViewDelegate {
typealias StateType = AppState
enum Action {
case setUsesVcsIgnores(Bool)
case open(URL)
case close
}
let scanCondition = NSCondition()
var pauseScan = false
@objc dynamic private(set) var unsortedScoredUrls = [ScoredUrl]()
// Call this only when quitting
func cleanUp() {
self.searchServicePerRootUrl.values.forEach { $0.cleanUp() }
self.searchServicePerRootUrl.removeAll()
}
@objc func useVcsAction(_: Any?) {
self.scanToken = Token()
self.currentSearchService?.stopScanScore()
self.endProgress()
self.unsortedScoredUrls.removeAll()
self.emit(.setUsesVcsIgnores(self.useVcsIgnoresCheckBox.boolState))
}
required init(source: Observable<StateType>, emitter: ActionEmitter, state: StateType) {
self.emit = emitter.typedEmit()
self.windowController = NSWindowController(windowNibName: NSNib.Name("OpenQuicklyWindow"))
self.searchStream = self.searchField.rx
.text.orEmpty
.throttle(0.2, scheduler: MainScheduler.instance)
.throttle(.milliseconds(1 * 500), latest: true, scheduler: MainScheduler.instance)
.distinctUntilChanged()
super.init()
self.window.delegate = self
self.filterOpQueue.qualityOfService = .userInitiated
self.filterOpQueue.name = "open-quickly-filter-operation-queue"
self.configureWindow()
self.addViews()
source
.observeOn(MainScheduler.instance)
.subscribe(onNext: { state in
guard state.openQuickly.open else {
self.windowController.close()
return
}
if self.window.isKeyWindow {
// already open, so do nothing
return
}
self.cwd = state.openQuickly.cwd
self.cwdPathCompsCount = self.cwd.pathComponents.count
self.cwdControl.url = self.cwd
self.flatFileItemsSource = FileItemUtils.flatFileItems(
of: state.openQuickly.cwd,
ignorePatterns: state.openQuickly.ignorePatterns,
ignoreToken: state.openQuickly.ignoreToken,
root: state.openQuickly.root
)
self.searchStream
.subscribe(onNext: { pattern in
self.pattern = pattern
self.resetAndAddFilterOperation()
})
.disposed(by: self.perSessionDisposeBag)
self.flatFileItemsSource
.subscribeOn(self.scheduler)
.do(onNext: { items in
self.scanCondition.lock()
while self.pauseScan {
self.scanCondition.wait()
}
self.scanCondition.unlock()
//
self.flatFileItems.append(contentsOf: items)
self.resetAndAddFilterOperation()
})
.observeOn(MainScheduler.instance)
.subscribe(onNext: { items in
self.count += items.count
self.countField.stringValue = "\(self.count) items"
})
.disposed(by: self.perSessionDisposeBag)
self.windowController.showWindow(self)
})
.subscribe(onNext: { [weak self] state in self?.subscription(state) })
.disposed(by: self.disposeBag)
}
func reloadFileView(withScoredItems items: [ScoredFileItem]) {
self.fileViewItems = items
self.fileView.reloadData()
}
func startProgress() {
self.progressIndicator.startAnimation(self)
}
func endProgress() {
self.progressIndicator.stopAnimation(self)
}
// MARK: - Private
private let emit: (Action) -> Void
private let disposeBag = DisposeBag()
private var flatFileItemsSource = Observable<[FileItem]>.empty()
private(set) var cwd = FileUtils.userHomeUrl
private var cwdPathCompsCount = 0
// FIXME: migrate to State later...
private(set) var pattern = ""
private(set) var flatFileItems = [FileItem]()
private(set) var fileViewItems = [ScoredFileItem]()
private var count = 0
private let searchStream: Observable<String>
private var perSessionDisposeBag = DisposeBag()
private let filterOpQueue = OperationQueue()
private var cwdPathCompsCount = 0
private var usesVcsIgnores = true
private var scanToken = Token()
private let scheduler = ConcurrentDispatchQueueScheduler(qos: .userInitiated)
private var searchServicePerRootUrl: [URL: FuzzySearchService] = [:]
private var currentSearchService: FuzzySearchService?
private let scoredUrlsController = NSArrayController()
private let windowController: NSWindowController
private let titleField = NSTextField.defaultTitleTextField()
private let useVcsIgnoresCheckBox = NSButton(forAutoLayout: ())
private let searchField = NSTextField(forAutoLayout: ())
private let progressIndicator = NSProgressIndicator(forAutoLayout: ())
private let cwdControl = NSPathControl(forAutoLayout: ())
private let countField = NSTextField(forAutoLayout: ())
private let fileView = NSTableView.standardTableView()
private let searchStream: Observable<String>
private let log = OSLog(subsystem: Defs.loggerSubsystem,
category: Defs.LoggerCategory.uiComponents)
private var window: NSWindow {
return self.windowController.window!
private var window: NSWindow { self.windowController.window! }
private func configureWindow() {
[
NSWindow.ButtonType.closeButton,
NSWindow.ButtonType.miniaturizeButton,
NSWindow.ButtonType.zoomButton,
].forEach { self.window.standardWindowButton($0)?.isHidden = true }
self.window.delegate = self
}
private func resetAndAddFilterOperation() {
self.filterOpQueue.cancelAllOperations()
let op = OpenQuicklyFilterOperation(forOpenQuickly: self)
self.filterOpQueue.addOperation(op)
private func subscription(_ state: StateType) {
self.updateRootUrls(state: state)
guard state.openQuickly.open, let curWinState = state.currentMainWindow else {
self.windowController.close()
return
}
let windowIsOpen = self.window.isKeyWindow
// The window is open and the user changed the setting
if self.usesVcsIgnores != curWinState.usesVcsIgnores && windowIsOpen {
self.usesVcsIgnores = curWinState.usesVcsIgnores
self.useVcsIgnoresCheckBox.boolState = curWinState.usesVcsIgnores
self.scanToken = Token()
self.currentSearchService?.usesVcsIgnores = self.usesVcsIgnores
self.unsortedScoredUrls.removeAll()
let pattern = self.searchField.stringValue
if pattern.count >= 2 { self.scanAndScore(pattern) }
return
}
// already open, so do nothing
if windowIsOpen { return }
self.usesVcsIgnores = curWinState.usesVcsIgnores
// TODO: read global vcs ignores
self.prepareSearch(curWinState: curWinState)
self.windowController.showWindow(nil)
self.searchField.beFirstResponder()
}
private func prepareSearch(curWinState: MainWindow.State) {
self.usesVcsIgnores = curWinState.usesVcsIgnores
self.useVcsIgnoresCheckBox.boolState = curWinState.usesVcsIgnores
let cwd = curWinState.cwd
self.currentSearchService = self.searchServicePerRootUrl[cwd]
self.cwdPathCompsCount = cwd.pathComponents.count
self.cwdControl.url = cwd
self.searchStream
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] pattern in
self?.scanAndScore(pattern)
})
.disposed(by: self.perSessionDisposeBag)
}
private func reset() {
self.scanToken = Token()
self.currentSearchService?.stopScanScore()
self.endProgress()
self.unsortedScoredUrls.removeAll()
self.searchField.stringValue = ""
self.perSessionDisposeBag = DisposeBag()
}
private func scanAndScore(_ pattern: String) {
self.currentSearchService?.stopScanScore()
guard pattern.count >= 2 else {
self.unsortedScoredUrls.removeAll()
return
}
self.scanToken = Token()
let localToken = self.scanToken
self.unsortedScoredUrls.removeAll()
self.currentSearchService?.scanScore(
for: pattern,
beginCallback: { self.startProgress() },
endCallback: { self.endProgress() }
) { scoredUrls in
DispatchQueue.main.async {
guard localToken == self.scanToken else { return }
self.unsortedScoredUrls.append(contentsOf: scoredUrls)
}
}
}
private func startProgress() { self.progressIndicator.startAnimation(self) }
private func endProgress() { self.progressIndicator.stopAnimation(self) }
private func updateRootUrls(state: AppState) {
let urlsToMonitor = Set(state.mainWindows.map { $1.cwd })
let currentUrls = Set(self.searchServicePerRootUrl.map { url, _ in url })
let newUrls = urlsToMonitor.subtracting(currentUrls)
let obsoleteUrls = currentUrls.subtracting(urlsToMonitor)
newUrls.forEach { url in
self.log.info("Adding \(url) and its service.")
guard let service = try? FuzzySearchService(root: url) else {
self.log.error("Could not create FileService for \(url)")
return
}
self.searchServicePerRootUrl[url] = service
}
obsoleteUrls.forEach { url in
self.log.info("Removing \(url) and its service.")
self.searchServicePerRootUrl.removeValue(forKey: url)
}
}
private func addViews() {
let useVcsIg = self.useVcsIgnoresCheckBox
useVcsIg.setButtonType(.switch)
useVcsIg.controlSize = .mini
useVcsIg.title = "Use VCS Ignores"
useVcsIg.target = self
useVcsIg.action = #selector(OpenQuicklyWindow.useVcsAction)
let title = self.titleField
title.font = .boldSystemFont(ofSize: 11)
title.stringValue = "Open Quickly"
let searchField = self.searchField
searchField.rx.delegate.setForwardToDelegate(self, retainDelegate: false)
@ -161,7 +233,17 @@ class OpenQuicklyWindow: NSObject,
let fileView = self.fileView
fileView.intercellSpacing = CGSize(width: 4, height: 4)
fileView.dataSource = self
let c = self.scoredUrlsController
c.avoidsEmptySelection = false
c.preservesSelection = true
c.objectClass = ScoredUrl.self
c.sortDescriptors = [NSSortDescriptor(key: "score", ascending: false)]
c.automaticallyRearrangesObjects = true
c.bind(.contentArray, to: self, withKeyPath: "unsortedScoredUrls")
fileView.bind(.content, to: c, withKeyPath: "arrangedObjects")
fileView.bind(.selectionIndexes, to: c, withKeyPath: "selectionIndexes")
fileView.delegate = self
let fileScrollView = NSScrollView.standardScrollView()
@ -176,26 +258,23 @@ class OpenQuicklyWindow: NSObject,
cwdControl.cell?.font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize)
cwdControl.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
let countField = self.countField
countField.isEditable = false
countField.isBordered = false
countField.alignment = .right
countField.backgroundColor = NSColor.clear
countField.stringValue = "0 items"
let contentView = self.window.contentView!
contentView.addSubview(title)
contentView.addSubview(useVcsIg)
contentView.addSubview(searchField)
contentView.addSubview(progressIndicator)
contentView.addSubview(fileScrollView)
contentView.addSubview(cwdControl)
contentView.addSubview(countField)
searchField.autoPinEdge(toSuperviewEdge: .top, withInset: 8)
searchField.autoPinEdge(toSuperviewEdge: .right, withInset: 8)
searchField.autoPinEdge(toSuperviewEdge: .left, withInset: 8)
title.autoPinEdge(toSuperviewEdge: .left, withInset: 8)
title.autoPinEdge(toSuperviewEdge: .top, withInset: 8)
progressIndicator.autoAlignAxis(.horizontal, toSameAxisOf: searchField)
progressIndicator.autoPinEdge(.right, to: .right, of: searchField, withOffset: -4)
useVcsIg.autoAlignAxis(.horizontal, toSameAxisOf: title)
useVcsIg.autoPinEdge(toSuperviewEdge: .right, withInset: 8)
searchField.autoPinEdge(.top, to: .bottom, of: useVcsIg, withOffset: 8)
searchField.autoPinEdge(.left, to: .left, of: title)
searchField.autoPinEdge(.right, to: .right, of: useVcsIg)
fileScrollView.autoPinEdge(.top, to: .bottom, of: searchField, withOffset: 8)
fileScrollView.autoPinEdge(toSuperviewEdge: .left, withInset: -1)
@ -203,23 +282,12 @@ class OpenQuicklyWindow: NSObject,
fileScrollView.autoSetDimension(.height, toSize: 200, relation: .greaterThanOrEqual)
cwdControl.autoPinEdge(.top, to: .bottom, of: fileScrollView, withOffset: 4)
// cwdControl.autoPinEdge(toSuperviewEdge: .bottom)
cwdControl.autoPinEdge(toSuperviewEdge: .left, withInset: 2)
cwdControl.autoPinEdge(toSuperviewEdge: .bottom, withInset: 4)
// countField.autoPinEdge(toSuperviewEdge: .bottom)
countField.autoPinEdge(.top, to: .bottom, of: fileScrollView, withOffset: 4)
countField.autoPinEdge(toSuperviewEdge: .right, withInset: 2)
countField.autoPinEdge(.left, to: .right, of: cwdControl, withOffset: 4)
}
}
// MARK: - NSTableViewDataSource
extension OpenQuicklyWindow {
@objc(numberOfRowsInTableView:)
func numberOfRows(in _: NSTableView) -> Int {
return self.fileViewItems.count
progressIndicator.autoAlignAxis(.horizontal, toSameAxisOf: cwdControl)
progressIndicator.autoPinEdge(.left, to: .right, of: cwdControl, withOffset: 4)
progressIndicator.autoPinEdge(toSuperviewEdge: .right, withInset: 8)
}
}
@ -230,14 +298,21 @@ extension OpenQuicklyWindow {
return OpenQuicklyFileViewRow()
}
@objc(tableView: viewForTableColumn:row:)
func tableView(_ tableView: NSTableView, viewFor _: NSTableColumn?, row: Int) -> NSView? {
let cachedCell = (tableView.makeView(
withIdentifier: NSUserInterfaceItemIdentifier("file-view-row"), owner: self) as? ImageAndTextTableCell
let cachedCell = (
tableView.makeView(
withIdentifier: NSUserInterfaceItemIdentifier("file-view-row"),
owner: self
) as? ImageAndTextTableCell
)?.reset()
let cell = cachedCell ?? ImageAndTextTableCell(withIdentifier: "file-view-row")
let url = self.fileViewItems[row].url
guard let sortedUrls = self.scoredUrlsController.arrangedObjects as? Array<ScoredUrl> else {
self.log.error("Could not convert arranged objects to [ScoredUrl].")
return nil
}
let url = sortedUrls[row].url
cell.attributedText = self.rowText(for: url as URL)
cell.image = FileUtils.icon(forUrl: url)
@ -249,9 +324,7 @@ extension OpenQuicklyWindow {
let truncatedPathComps = pathComps[self.cwdPathCompsCount..<pathComps.count]
let name = truncatedPathComps.last!
if truncatedPathComps.dropLast().isEmpty {
return NSMutableAttributedString(string: name)
}
if truncatedPathComps.dropLast().isEmpty { return NSMutableAttributedString(string: name) }
let rowText: NSMutableAttributedString
let pathInfo = truncatedPathComps.dropLast().reversed().joined(separator: " / ")
@ -267,16 +340,24 @@ extension OpenQuicklyWindow {
// MARK: - NSTextFieldDelegate
extension OpenQuicklyWindow {
@objc(control: textView:doCommandBySelector:)
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
func control(
_ control: NSControl,
textView: NSTextView,
doCommandBy commandSelector: Selector
) -> Bool {
switch commandSelector {
case NSSelectorFromString("cancelOperation:"):
self.window.performClose(self)
return true
case NSSelectorFromString("insertNewline:"):
// TODO open the url
self.emit(.open(self.fileViewItems[self.fileView.selectedRow].url))
guard let sortedUrls = self.scoredUrlsController.arrangedObjects as? Array<ScoredUrl> else {
self.log.error("Could not convert arranged objects to [ScoredUrl].")
return true
}
self.emit(.open(sortedUrls[self.fileView.selectedRow].url))
self.window.performClose(self)
return true
@ -290,6 +371,7 @@ extension OpenQuicklyWindow {
default:
return false
}
}
@ -320,25 +402,7 @@ extension OpenQuicklyWindow {
return false
}
func windowWillClose(_: Notification) {
self.endProgress()
func windowWillClose(_: Notification) { self.reset() }
self.filterOpQueue.cancelAllOperations()
self.perSessionDisposeBag = DisposeBag()
self.pauseScan = false
self.count = 0
self.pattern = ""
self.flatFileItems = []
self.fileViewItems = []
self.fileView.reloadData()
self.searchField.stringValue = ""
self.countField.stringValue = "0 items"
}
func windowDidResignKey(_: Notification) {
self.window.performClose(self)
}
func windowDidResignKey(_: Notification) { self.window.performClose(self) }
}

View File

@ -29,7 +29,7 @@ class PrefPane: NSView {
extension PrefPane {
func paneTitleTextField(title: String) -> NSTextField {
let field = defaultTitleTextField()
let field = NSTextField.defaultTitleTextField()
field.font = NSFont.boldSystemFont(ofSize: 16)
field.alignment = .left;
field.stringValue = title
@ -37,7 +37,7 @@ extension PrefPane {
}
func titleTextField(title: String) -> NSTextField {
let field = defaultTitleTextField()
let field = NSTextField.defaultTitleTextField()
field.alignment = .right;
field.stringValue = title
return field
@ -65,12 +65,4 @@ extension PrefPane {
button.target = self
button.action = action
}
private func defaultTitleTextField() -> NSTextField {
let field = NSTextField(forAutoLayout: ())
field.backgroundColor = NSColor.clear;
field.isEditable = false;
field.isBordered = false;
return field
}
}

View File

@ -8,34 +8,6 @@ import NvimView
class PrefUtils {
private static let whitespaceCharSet = CharacterSet.whitespaces
static func ignorePatterns(fromString str: String) -> Set<FileItemIgnorePattern> {
if str.trimmingCharacters(in: self.whitespaceCharSet).count == 0 {
return Set()
}
let patterns: [FileItemIgnorePattern] = str
.components(separatedBy: ",")
.compactMap {
let trimmed = $0.trimmingCharacters(in: self.whitespaceCharSet)
if trimmed.count == 0 {
return nil
}
return FileItemIgnorePattern(pattern: trimmed)
}
return Set(patterns)
}
static func ignorePatternString(fromSet set: Set<FileItemIgnorePattern>) -> String {
return Array(set)
.map { $0.pattern }
.sorted()
.joined(separator: ", ")
}
static func value<T>(from dict: [String: Any], for key: String) -> T? {
return dict[key] as? T
}

View File

@ -1,25 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import RxSwift
class ScoredFileItem: Comparable {
let score: Int
let url: URL
init(score: Int, url: URL) {
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
}

23
VimR/VimR/ScoredUrl.h Normal file
View File

@ -0,0 +1,23 @@
//
// Created by Tae Won Ha on 05.01.20.
// Copyright (c) 2020 Tae Won Ha. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ScoredUrl : NSObject
@property (readonly, nonnull) NSURL *url;
@property (readonly) NSInteger score;
- (BOOL)isEqual:(id _Nullable)other;
- (BOOL)isEqualToUrl:(ScoredUrl * _Nullable)url;
- (NSUInteger)hash;
- (instancetype _Nonnull)initWithUrl:(NSURL * _Nonnull)url score:(NSInteger)score;
- (NSString * _Nonnull)description;
+ (instancetype _Nonnull)urlWithUrl:(NSURL * _Nonnull)url score:(NSInteger)score;
@end

62
VimR/VimR/ScoredUrl.m Normal file
View File

@ -0,0 +1,62 @@
//
// Created by Tae Won Ha on 05.01.20.
// Copyright (c) 2020 Tae Won Ha. All rights reserved.
//
#import "ScoredUrl.h"
@implementation ScoredUrl {
}
- (BOOL)isEqual:(id)other {
if (other == self)
return YES;
if (!other || ![[other class] isEqual:[self class]])
return NO;
return [self isEqualToUrl:other];
}
- (BOOL)isEqualToUrl:(ScoredUrl *)url {
if (self == url)
return YES;
if (url == nil)
return NO;
if (self.url != url.url && ![self.url isEqual:url.url])
return NO;
if (self.score != url.score)
return NO;
return YES;
}
- (NSUInteger)hash {
NSUInteger hash = [self.url hash];
hash = hash * 31u + self.score;
return hash;
}
- (NSString *)description {
NSMutableString *description
= [NSMutableString stringWithFormat:@"<%@: ", NSStringFromClass([self class])];
[description appendFormat:@"self.url=%@", self.url.path];
[description appendFormat:@", self.score=%li", self.score];
[description appendString:@">"];
return description;
}
- (instancetype)initWithUrl:(NSURL *)url score:(NSInteger)score {
self = [super init];
if (!self) {return nil;}
_url = url;
_score = score;
return self;
}
+ (instancetype)urlWithUrl:(NSURL *)url score:(NSInteger)score {
return [[self alloc] initWithUrl:url score:score];
}
@end

View File

@ -1,31 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
class Scorer {
static func score(_ target: String, pattern: String) -> Int {
let fuzzy = Matcher.fuzzyIgnoringCase(target, pattern: pattern)
let upper = Matcher.numberOfUppercaseMatches(target, pattern: pattern)
let exactMatch = Matcher.exactMatchIgnoringCase(target, pattern: pattern)
let wf = Matcher.wagnerFisherDistance(target, pattern: pattern)
let exactScore: Int
switch exactMatch {
case .none:
exactScore = 0
case .exact:
return 1000
case .prefix, .contains, .suffix:
exactScore = 5
}
return exactScore
+ 10 * fuzzy
+ 5 * upper
- wf
}
}

View File

@ -41,6 +41,10 @@ struct AppState: Codable {
var currentMainWindowUuid: UUID?
var mainWindows: [UUID: MainWindow.State] = [:]
var currentMainWindow: MainWindow.State? {
guard let uuid = self.currentMainWindowUuid else { return nil }
return self.mainWindows[uuid]
}
var openQuickly = OpenQuicklyWindow.State.default
@ -73,34 +77,27 @@ extension OpenQuicklyWindow {
struct State: Codable {
static let `default` = State()
static let defaultIgnorePatterns = Set(["*/.git", "*.o", "*.d", "*.dia"].map(FileItemIgnorePattern.init))
enum CodingKeys: String, CodingKey {
case ignorePatterns = "ignore-patterns"
case defaultUsesVcsIgnore = "default-uses-vcs-ignores"
}
let root = FileItem(URL(fileURLWithPath: "/", isDirectory: true))
var flatFileItems = Observable<[FileItem]>.empty()
var cwd = FileUtils.userHomeUrl
var ignorePatterns = State.defaultIgnorePatterns
var ignoreToken = Token()
var defaultUsesVcsIgnores = true
var open = false
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let patternsAsString = try container.decodeIfPresent(String.self, forKey: .ignorePatterns) {
self.ignorePatterns = FileItemIgnorePattern.from(string: patternsAsString)
} else {
self.ignorePatterns = State.defaultIgnorePatterns
}
self.defaultUsesVcsIgnores = try container.decode(
forKey: .defaultUsesVcsIgnore,
default: OpenQuicklyWindow.State.default.defaultUsesVcsIgnores
)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(FileItemIgnorePattern.toString(self.ignorePatterns), forKey: .ignorePatterns)
try container.encode(self.defaultUsesVcsIgnores, forKey: .defaultUsesVcsIgnore)
}
private init() {
@ -285,6 +282,8 @@ extension MainWindow {
var cliPipePath: String?
var envDict: [String: String]?
var usesVcsIgnores = true
var isLeftOptionMeta = false
var isRightOptionMeta = false

View File

@ -24,12 +24,8 @@ class UiRoot: UiComponent {
self.emitter = emitter
self.emit = emitter.typedEmit()
self.fileMonitor = FileMonitor(source: source,
emitter: emitter,
state: state)
self.openQuicklyWindow = OpenQuicklyWindow(source: source,
emitter: emitter,
state: state)
self.fileMonitor = FileMonitor(source: source, emitter: emitter, state: state)
self.openQuicklyWindow = OpenQuicklyWindow(source: source, emitter: emitter, state: state)
self.prefWindow = PrefWindow(source: source, emitter: emitter, state: state)
source
@ -71,15 +67,27 @@ class UiRoot: UiComponent {
.disposed(by: self.disposeBag)
}
// The following should only be used when Cmd-Q'ing
func hasBlockedWindows() -> Bool {
for mainWin in self.mainWindows.values {
if mainWin.neoVimView.isBlocked().syncValue() == true { return true }
}
return false
}
// The following should only be used when Cmd-Q'ing
func prepareQuit() {
self.mainWindows.values.forEach { $0.prepareClosing() }
try? Completable
.concat(self.mainWindows.values.map { $0.quitNeoVimWithoutSaving() })
.wait()
if !self.mainWindows.isEmpty {
try? Completable
.concat(self.mainWindows.values.map { $0.quitNeoVimWithoutSaving() })
.wait()
}
self.mainWindows.values.forEach { $0.waitTillNvimExits() }
self.openQuicklyWindow.cleanUp()
}
private let source: Observable<AppState>

View File

@ -1,65 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import XCTest
import Nimble
@testable import VimR
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

@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>SNAPSHOT-330</string>
<string>SNAPSHOT-331</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>330</string>
<string>331</string>
</dict>
</plist>

View File

@ -1,42 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import XCTest
import Nimble
class MatcherTest: XCTestCase {
let target = "UserDefaultContextTest.swift"
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("SwiftNeoVimNeoVimView.swift", pattern: "swnvv")).to(equal(4))
expect(Matcher.numberOfUppercaseMatches(self.target, pattern: "xct")).to(equal(2))
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")).to(equal(6 + 5))
expect(Matcher.fuzzyIgnoringCase(self.target, pattern: "uco-tft")).to(equal(3 + 5))
}
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))
}
}

View File

@ -1,32 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import XCTest
import Nimble
class ScorerTest: XCTestCase {
func testScore1() {
let pattern = "sw/nvv".replacingOccurrences(of: "/", with: "")
let targets = [
"SwiftNeoVim/NeoVimView.swift",
"build/Release/NeoVimServer.dSYM/Contents/Resources/DWARF/NeoVimServer",
].map { $0.replacingOccurrences(of: "/", with: "") }
expect(Scorer.score(targets[0], pattern: pattern)).to(beGreaterThan(Scorer.score(targets[1], pattern: pattern)))
}
func testScore2() {
let pattern = "nvv"
let targets = [
"NeoVimView.swift",
"NeoVimViewDelegate.swift",
"NeoVimAgent",
]
expect(Scorer.score(targets[0], pattern: pattern)).to(beGreaterThan(Scorer.score(targets[1], pattern: pattern)))
expect(Scorer.score(targets[1], pattern: pattern)).to(beGreaterThan(Scorer.score(targets[2], pattern: pattern)))
}
}

View File

@ -7,27 +7,26 @@
<description>Most recent changes with links to updates for VimR.</description>
<language>en</language>
<item>
<title>SNAPSHOT-330</title>
<title>SNAPSHOT-331</title>
<description><![CDATA[
<ul>
<li>Bugfix: Forward search in Markdown preview does not work.</li>
<li>Dependencies updates:<ul>
<li>IBM-Swift/BlueSocket 1.0.52</li>
<li>elegantchaos/DictionaryCoding 1.0.7</li>
<li>Improve Open Quickly<ul>
<li>Use <a href="https://github.com/ggreer/the_silver_searcher">The Silver Searcher</a>'s ignore mechanism</li>
<li>Use <a href="https://github.com/MaskRay/ccls">ccls</a>' fuzzy search</li>
</ul>
</li>
</ul>
]]></description>
<releaseNotesLink>
https://github.com/qvacua/vimr/releases/tag/snapshot/330
https://github.com/qvacua/vimr/releases/tag/snapshot/331
</releaseNotesLink>
<pubDate>2019-12-25T17:33:57.259799</pubDate>
<pubDate>2020-01-18T21:43:43.353075</pubDate>
<minimumSystemVersion>10.12.0</minimumSystemVersion>
<enclosure url="https://github.com/qvacua/vimr/releases/download/snapshot/330/VimR-SNAPSHOT-330.tar.bz2"
sparkle:version="330"
sparkle:shortVersionString="SNAPSHOT-330"
sparkle:dsaSignature="MC0CFH/R8kd4LFqgSPqM5cZ7NWlxWcclAhUA3Kn4mHRf/HcBdMtxWhbJabBCrnQ="
length="14508630"
<enclosure url="https://github.com/qvacua/vimr/releases/download/snapshot/331/VimR-SNAPSHOT-331.tar.bz2"
sparkle:version="331"
sparkle:shortVersionString="SNAPSHOT-331"
sparkle:dsaSignature="MC4CFQCMHcdbHe3rjJMA/8IG8y/gMHLm4AIVANjMwduRWinKIgkEFrV1c90LNemF"
length="14655979"
type="application/octet-stream"/>
</item>
</channel>

View File

@ -10,12 +10,12 @@ export PATH=/usr/local/bin:$PATH
readonly publish=${publish:?"true or false"}
readonly branch=${branch:?"Eg develop"}
readonly release_notes=${release_notes:?"Some (multiline) markdown text"}
readonly is_snapshot=${is_snapshot:?"true or false"}
readonly update_appcast=${update_appcast:?"true or false"}
readonly update_snapshot_appcast_for_release=${update_snapshot_appcast_for_release:?"true or false"}
export marketing_version=${marketing_version:?"0.29.0"}
export marketing_version=${marketing_version}
readonly release_notes=${release_notes}
if [[ "${is_snapshot}" = false ]] && [[ "${marketing_version}" == "" ]] ; then

View File

@ -7,12 +7,104 @@ pushd "$(dirname "${BASH_SOURCE[0]}")/.." > /dev/null
readonly deployment_target_file="./resources/macos_deployment_target.txt"
readonly deployment_target=$(cat ${deployment_target_file})
readonly gettext_version="0.20.1"
readonly pcre_version="8.43"
readonly xz_version="5.2.4"
readonly ag_version="2.2.0"
build_ag () {
pushd .deps > /dev/null
curl -L -o ag.tar.gz https://github.com/ggreer/the_silver_searcher/archive/${ag_version}.tar.gz
tar xf ag.tar.gz
mv the_silver_searcher-${ag_version} ag
pushd ag > /dev/null
./autogen.sh
xz_include=$(pwd)/../../third-party/libxz/include
pcre_include=$(pwd)/../../third-party/libpcre/include
./configure CFLAGS="-mmacosx-version-min=${deployment_target} -I${xz_include} -I${pcre_include}" \
LDFLAGS="-L$(pwd)/../../third-party/libxz/lib -L$(pwd)/../../third-party/libpcre/lib" \
MACOSX_DEPLOYMENT_TARGET=${deployment_target}
pushd src > /dev/null
cc -c ignore.c log.c options.c print.c scandir.c search.c lang.c util.c decompress.c zfile.c
ar -crs libag.a ignore.o log.o options.o print.o scandir.o search.o lang.o util.o decompress.o zfile.o
mkdir -p $(pwd)/../../../third-party/libag/lib
mv libag.a $(pwd)/../../../third-party/libag/lib
mkdir -p $(pwd)/../../../third-party/libag/include
cp *.h $(pwd)/../../../third-party/libag/include
popd > /dev/null
popd > /dev/null
popd > /dev/null
}
build_xz () {
pushd .deps > /dev/null
curl -L -o xz.tar.gz https://tukaani.org/xz/xz-${xz_version}.tar.gz
tar xf xz.tar.gz
mv xz-${xz_version} xz
pushd xz > /dev/null
# configure from https://github.com/Homebrew/homebrew-core/blob/c9882801013d6bc5202b91ef56ff5838d18bbab2/Formula/xz.rb
./configure CFLAGS="-mmacosx-version-min=${deployment_target}" MACOSX_DEPLOYMENT_TARGET=${deployment_target} \
--disable-debug \
--disable-dependency-tracking \
--disable-silent-rules \
--prefix=$(pwd)/../../third-party/libxz
make
make install
rm -rf $(pwd)/../../third-party/libxz/bin
rm -rf $(pwd)/../../third-party/libxz/share
popd > /dev/null
popd > /dev/null
}
build_pcre () {
pushd .deps > /dev/null
curl -L -o pcre.tar.bz2 https://ftp.pcre.org/pub/pcre/pcre-${pcre_version}.tar.bz2
tar xf pcre.tar.bz2
mv pcre-${pcre_version} pcre
pushd pcre > /dev/null
# configure from https://github.com/Homebrew/homebrew-core/blob/c9882801013d6bc5202b91ef56ff5838d18bbab2/Formula/pcre.rb
./configure CFLAGS="-mmacosx-version-min=${deployment_target}" MACOSX_DEPLOYMENT_TARGET=${deployment_target} \
--disable-dependency-tracking \
--prefix=$(pwd)/../../third-party/libpcre \
--enable-utf8 \
--enable-pcre8 \
--enable-pcre16 \
--enable-pcre32 \
--enable-unicode-properties \
--enable-pcregrep-libz \
--enable-pcregrep-libbz2 \
--enable-jit
make
make install
rm -rf $(pwd)/../../third-party/libpcre/bin
rm -rf $(pwd)/../../third-party/libpcre/share
popd > /dev/null
popd > /dev/null
}
build_vimr_deps () {
rm -rf third-party
mkdir third-party
rm -rf .deps
mkdir .deps
build_pcre
build_xz
build_ag
}
build_gettext () {
pushd NvimView > /dev/null
mkdir -p third-party/libintl
rm -rf .deps
mkdir .deps
pushd .deps > /dev/null
curl -o gettext.tar.xz https://ftp.gnu.org/gnu/gettext/gettext-${gettext_version}.tar.xz
curl -L -o gettext.tar.xz https://ftp.gnu.org/gnu/gettext/gettext-${gettext_version}.tar.xz
tar xf gettext.tar.xz
mv gettext-${gettext_version} gettext
@ -52,3 +144,7 @@ popd > /dev/null
popd > /dev/null
echo "### Built deps"
}
build_gettext
build_vimr_deps

View File

@ -5,10 +5,10 @@ import io
import re
from string import Template
NVIM_AUEVENTS_ENUM_FILE = "./neovim/build/include/auevents_enum.generated.h"
# Assume that we're in $REPO_ROOT/NvimView
NVIM_AUEVENTS_ENUM_FILE = "./neovim/build/include/auevents_enum.generated.h"
SWIFT_TEMPLATE_FILE = "../resources/autocmds.template.swift"
SWIFT_AUTOCMDS_FILE = './NvimView/NvimAutoCommandEvent.generated.swift'
def convert(line: str) -> (str, str):
@ -32,8 +32,6 @@ def swift_autocmds(version: str, template_string: str) -> str:
if __name__ == '__main__':
result_file_path = SWIFT_AUTOCMDS_FILE
version = os.environ['version']
with io.open(SWIFT_TEMPLATE_FILE, "r") as template, \
io.open(result_file_path, 'w') as header_file:
header_file.write(swift_autocmds(version, template.read()))
with io.open(SWIFT_TEMPLATE_FILE, "r") as template:
print(swift_autocmds(version, template.read()))

60
bin/generate_cursor_shape.py Executable file
View File

@ -0,0 +1,60 @@
#!/usr/local/bin/python3
import io
import os
import re
from string import Template
# Assume that we're in $REPO_ROOT/NvimView
NVIM_CURSOR_SHAPE_ENUM_FILE = "./neovim/src/nvim/cursor_shape.h"
SWIFT_TEMPLATE_FILE = "../resources/cursor_shape.template.swift"
SHAPE_NAMES = {
"SHAPE_IDX_N": (0, "normal"),
"SHAPE_IDX_V": (1, "visual"),
"SHAPE_IDX_I": (2, "insert"),
"SHAPE_IDX_R": (3, "replace"),
"SHAPE_IDX_C": (4, "cmdlineNormal"),
"SHAPE_IDX_CI": (5, "cmdlineInsert"),
"SHAPE_IDX_CR": (6, "cmdlineReplace"),
"SHAPE_IDX_O": (7, "operatorPending"),
"SHAPE_IDX_VE": (8, "visualExclusive"),
"SHAPE_IDX_CLINE": (9, "onCmdline"),
"SHAPE_IDX_STATUS": (10, "onStatusLine"),
"SHAPE_IDX_SDRAG": (11, "draggingStatusLine"),
"SHAPE_IDX_VSEP": (12, "onVerticalSepLine"),
"SHAPE_IDX_VDRAG": (13, "draggingVerticalSepLine"),
"SHAPE_IDX_MORE": (14, "more"),
"SHAPE_IDX_MOREL": (15, "moreLastLine"),
"SHAPE_IDX_SM": (16, "showingMatchingParen"),
"SHAPE_IDX_TERM": (17, "termFocus"),
"SHAPE_IDX_COUNT": (18, "count"),
}
def are_shapes_same() -> bool:
with io.open(NVIM_CURSOR_SHAPE_ENUM_FILE, "r") as cursor_shape_header:
shape_regex = r'^\s*(SHAPE_IDX_[A-Z]+)\s*= ([0-9]+)'
shape_lines = [re.match(shape_regex, line) for line in cursor_shape_header]
nvim_shapes = [m.groups() for m in shape_lines if m]
return set(nvim_shapes) == set([(k, str(v[0])) for (k, v) in SHAPE_NAMES.items()])
def swift_shapes() -> str:
with io.open(SWIFT_TEMPLATE_FILE, "r") as template_file:
template = Template(template_file.read())
cases = "\n".join([f" case {v[1]} = {v[0]}" for (k, v) in SHAPE_NAMES.items()])
return template.substitute(
cursor_shapes=cases,
version=version
)
if __name__ == "__main__":
version = os.environ['version']
assert are_shapes_same()
print(swift_shapes())

View File

@ -27,7 +27,8 @@ pushd NvimView/neovim > /dev/null
popd > /dev/null
pushd NvimView
version=${nvim_version} ../bin/generate_autocmds.py
version=${nvim_version} ../bin/generate_autocmds.py > "./NvimView/NvimAutoCommandEvent.generated.swift"
version=${nvim_version} ../bin/generate_cursor_shape.py > "./NvimView/NvimCursorModeShape.generated.swift"
popd > /dev/null
popd > /dev/null

7
ci/README.md Normal file
View File

@ -0,0 +1,7 @@
* Install Jenkins (via brew)
* Install plugins
- Job DSL
- AnsiColor
* Set the `git` binary in *Manage Jenkins* -> *Global Tool Configuration*
* Set `PATH` for Jenkins (necessary for e.g. `git-lfs`) in *Manage Jenkins* -> *Configure System* -> *Global properties* -> *Environment variables"

View File

@ -1,5 +1,5 @@
// Auto generated for nvim ${version}
// See bin/generate_autocmds.sh
// See bin/generate_autocmds.py
enum NvimAutoCommandEvent: Int {

View File

@ -0,0 +1,8 @@
// Auto generated for nvim ${version}
// See bin/generate_cursor_shape.py
public enum CursorModeShape: UInt {
${cursor_shapes}
}

View File

@ -1,5 +1,9 @@
# 0.30.0-???
* Improve Open Quickly
- Use [The Silver Searcher](https://github.com/ggreer/the_silver_searcher)'s ignore mechanism
- Use [ccls](https://github.com/MaskRay/ccls)' fuzzy search
* Bugfix: VimR hangs when there are windows in which nvim is waiting for user input.
* Bugfix: Forward search in Markdown preview does not work.
* Dependencies updates:
- IBM-Swift/BlueSocket 1.0.52

120
third-party/libag/include/config.h vendored Normal file
View File

@ -0,0 +1,120 @@
/* src/config.h. Generated from config.h.in by configure. */
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Have dirent struct member d_namlen */
#define HAVE_DIRENT_DNAMLEN /**/
/* Have dirent struct member d_type */
#define HAVE_DIRENT_DTYPE /**/
/* Define to 1 if you have the <err.h> header file. */
#define HAVE_ERR_H 1
/* Define to 1 if you have the `fgetln' function. */
#define HAVE_FGETLN 1
/* Define to 1 if you have the `fopencookie' function. */
/* #undef HAVE_FOPENCOOKIE */
/* Define to 1 if you have the `getline' function. */
#define HAVE_GETLINE 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `shlwapi' library (-lshlwapi). */
/* #undef HAVE_LIBSHLWAPI */
/* Define to 1 if you have the <lzma.h> header file. */
#define HAVE_LZMA_H 1
/* Define to 1 if you have the `madvise' function. */
#define HAVE_MADVISE 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `pledge' function. */
/* #undef HAVE_PLEDGE */
/* Define to 1 if you have the `posix_fadvise' function. */
/* #undef HAVE_POSIX_FADVISE */
/* Define to 1 if you have the <pthread.h> header file. */
#define HAVE_PTHREAD_H 1
/* Have PTHREAD_PRIO_INHERIT. */
#define HAVE_PTHREAD_PRIO_INHERIT 1
/* Define to 1 if you have the `pthread_setaffinity_np' function. */
/* #undef HAVE_PTHREAD_SETAFFINITY_NP */
/* Define to 1 if you have the `realpath' function. */
#define HAVE_REALPATH 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strlcpy' function. */
#define HAVE_STRLCPY 1
/* Define to 1 if you have the `strndup' function. */
#define HAVE_STRNDUP 1
/* Define to 1 if you have the <sys/cpuset.h> header file. */
/* #undef HAVE_SYS_CPUSET_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `vasprintf' function. */
#define HAVE_VASPRINTF 1
/* Define to 1 if you have the <zlib.h> header file. */
#define HAVE_ZLIB_H 1
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "https://github.com/ggreer/the_silver_searcher/issues"
/* Define to the full name of this package. */
#define PACKAGE_NAME "the_silver_searcher"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "the_silver_searcher 2.2.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "the_silver_searcher"
/* Define to the home page for this package. */
#define PACKAGE_URL "https://github.com/ggreer/the_silver_searcher"
/* Define to the version of this package. */
#define PACKAGE_VERSION "2.2.0"
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
/* #undef PTHREAD_CREATE_JOINABLE */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Use CPU_SET macros */
/* #undef USE_CPU_SET */
/* Use PCRE JIT */
#define USE_PCRE_JIT /**/

26
third-party/libag/include/decompress.h vendored Normal file
View File

@ -0,0 +1,26 @@
#ifndef DECOMPRESS_H
#define DECOMPRESS_H
#include <stdio.h>
#include "config.h"
#include "log.h"
#include "options.h"
typedef enum {
AG_NO_COMPRESSION,
AG_GZIP,
AG_COMPRESS,
AG_ZIP,
AG_XZ,
} ag_compression_type;
ag_compression_type is_zipped(const void *buf, const int buf_len);
void *decompress(const ag_compression_type zip_type, const void *buf, const int buf_len, const char *dir_full_path, int *new_buf_len);
#if HAVE_FOPENCOOKIE
FILE *decompress_open(int fd, const char *mode, ag_compression_type ctype);
#endif
#endif

48
third-party/libag/include/ignore.h vendored Normal file
View File

@ -0,0 +1,48 @@
#ifndef IGNORE_H
#define IGNORE_H
#include <dirent.h>
#include <sys/types.h>
struct ignores {
char **extensions; /* File extensions to ignore */
size_t extensions_len;
char **names; /* Non-regex ignore lines. Sorted so we can binary search them. */
size_t names_len;
char **slash_names; /* Same but starts with a slash */
size_t slash_names_len;
char **regexes; /* For patterns that need fnmatch */
size_t regexes_len;
char **invert_regexes; /* For "!" patterns */
size_t invert_regexes_len;
char **slash_regexes;
size_t slash_regexes_len;
const char *dirname;
size_t dirname_len;
char *abs_path;
size_t abs_path_len;
struct ignores *parent;
};
typedef struct ignores ignores;
ignores *root_ignores;
extern const char *evil_hardcoded_ignore_files[];
extern const char *ignore_pattern_files[];
ignores *init_ignore(ignores *parent, const char *dirname, const size_t dirname_len);
void cleanup_ignore(ignores *ig);
void add_ignore_pattern(ignores *ig, const char *pattern);
void load_ignore_patterns(ignores *ig, const char *path);
int filename_filter(const char *path, const struct dirent *dir, void *baton);
int is_empty(ignores *ig);
#endif

36
third-party/libag/include/lang.h vendored Normal file
View File

@ -0,0 +1,36 @@
#ifndef LANG_H
#define LANG_H
#define MAX_EXTENSIONS 12
#define SINGLE_EXT_LEN 20
typedef struct {
const char *name;
const char *extensions[MAX_EXTENSIONS];
} lang_spec_t;
extern lang_spec_t langs[];
/**
Return the language count.
*/
size_t get_lang_count(void);
/**
Convert a NULL-terminated array of language extensions
into a regular expression of the form \.(extension1|extension2...)$
Caller is responsible for freeing the returned string.
*/
char *make_lang_regex(char *ext_array, size_t num_exts);
/**
Combine multiple file type extensions into one array.
The combined result is returned through *exts*;
*exts* is one-dimension array, which can contain up to 100 extensions;
The number of extensions that *exts* actually contain is returned.
*/
size_t combine_file_extensions(size_t *extension_index, size_t len, char **exts);
#endif

32
third-party/libag/include/log.h vendored Normal file
View File

@ -0,0 +1,32 @@
#ifndef LOG_H
#define LOG_H
#include <stdarg.h>
#include "config.h"
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
pthread_mutex_t print_mtx;
enum log_level {
LOG_LEVEL_DEBUG = 10,
LOG_LEVEL_MSG = 20,
LOG_LEVEL_WARN = 30,
LOG_LEVEL_ERR = 40,
LOG_LEVEL_NONE = 100
};
void set_log_level(enum log_level threshold);
void log_debug(const char *fmt, ...);
void log_msg(const char *fmt, ...);
void log_warn(const char *fmt, ...);
void log_err(const char *fmt, ...);
void vplog(const unsigned int level, const char *fmt, va_list args);
void plog(const unsigned int level, const char *fmt, ...);
#endif

105
third-party/libag/include/options.h vendored Normal file
View File

@ -0,0 +1,105 @@
#ifndef OPTIONS_H
#define OPTIONS_H
#include <getopt.h>
#include <sys/stat.h>
#include <pcre.h>
#define DEFAULT_AFTER_LEN 2
#define DEFAULT_BEFORE_LEN 2
#define DEFAULT_CONTEXT_LEN 2
#define DEFAULT_MAX_SEARCH_DEPTH 25
enum case_behavior {
CASE_DEFAULT, /* Changes to CASE_SMART at the end of option parsing */
CASE_SENSITIVE,
CASE_INSENSITIVE,
CASE_SMART,
CASE_SENSITIVE_RETRY_INSENSITIVE /* for future use */
};
enum path_print_behavior {
PATH_PRINT_DEFAULT, /* PRINT_TOP if > 1 file being searched, else PRINT_NOTHING */
PATH_PRINT_DEFAULT_EACH_LINE, /* PRINT_EACH_LINE if > 1 file being searched, else PRINT_NOTHING */
PATH_PRINT_TOP,
PATH_PRINT_EACH_LINE,
PATH_PRINT_NOTHING
};
typedef struct {
int ackmate;
pcre *ackmate_dir_filter;
pcre_extra *ackmate_dir_filter_extra;
size_t after;
size_t before;
enum case_behavior casing;
const char *file_search_string;
int match_files;
pcre *file_search_regex;
pcre_extra *file_search_regex_extra;
int color;
char *color_line_number;
char *color_match;
char *color_path;
int color_win_ansi;
int column;
int context;
int follow_symlinks;
int invert_match;
int literal;
int literal_starts_wordchar;
int literal_ends_wordchar;
size_t max_matches_per_file;
int max_search_depth;
int mmap;
int multiline;
int one_dev;
int only_matching;
char path_sep;
int path_to_ignore;
int print_break;
int print_count;
int print_filename_only;
int print_path;
int print_all_paths;
int print_line_numbers;
int print_long_lines; /* TODO: support this in print.c */
int passthrough;
pcre *re;
pcre_extra *re_extra;
int recurse_dirs;
int search_all_files;
int skip_vcs_ignores;
int search_binary_files;
int search_zip_files;
int search_hidden_files;
int search_stream; /* true if tail -F blah | ag */
int stats;
size_t stream_line_num; /* This should totally not be in here */
int match_found; /* This should totally not be in here */
ino_t stdout_inode;
char *query;
int query_len;
char *pager;
int paths_len;
int parallel;
int use_thread_affinity;
int vimgrep;
size_t width;
int word_regexp;
int workers;
} cli_options;
/* global options. parse_options gives it sane values, everything else reads from it */
cli_options opts;
typedef struct option option_t;
void usage(void);
void print_version(void);
void init_options(void);
void parse_options(int argc, char **argv, char **base_paths[], char **paths[]);
void cleanup_options(void);
#endif

26
third-party/libag/include/print.h vendored Normal file
View File

@ -0,0 +1,26 @@
#ifndef PRINT_H
#define PRINT_H
#include "util.h"
void print_init_context(void);
void print_cleanup_context(void);
void print_context_append(const char *line, size_t len);
void print_trailing_context(const char *path, const char *buf, size_t n);
void print_path(const char *path, const char sep);
void print_path_count(const char *path, const char sep, const size_t count);
void print_line(const char *buf, size_t buf_pos, size_t prev_line_offset);
void print_binary_file_matches(const char *path);
void print_file_matches(const char *path, const char *buf, const size_t buf_len, const match_t matches[], const size_t matches_len);
void print_line_number(size_t line, const char sep);
void print_column_number(const match_t matches[], size_t last_printed_match,
size_t prev_line_offset, const char sep);
void print_file_separator(void);
const char *normalize_path(const char *path);
#ifdef _WIN32
void windows_use_ansi(int use_ansi);
int fprintf_w32(FILE *fp, const char *format, ...);
#endif
#endif

20
third-party/libag/include/scandir.h vendored Normal file
View File

@ -0,0 +1,20 @@
#ifndef SCANDIR_H
#define SCANDIR_H
#include "ignore.h"
typedef struct {
const ignores *ig;
const char *base_path;
size_t base_path_len;
const char *path_start;
} scandir_baton_t;
typedef int (*filter_fp)(const char *path, const struct dirent *, void *);
int ag_scandir(const char *dirname,
struct dirent ***namelist,
filter_fp filter,
void *baton);
#endif

78
third-party/libag/include/search.h vendored Normal file
View File

@ -0,0 +1,78 @@
#ifndef SEARCH_H
#define SEARCH_H
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <pcre.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#endif
#include <sys/stat.h>
#include <unistd.h>
#include "config.h"
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#include "decompress.h"
#include "ignore.h"
#include "log.h"
#include "options.h"
#include "print.h"
#include "uthash.h"
#include "util.h"
size_t alpha_skip_lookup[256];
size_t *find_skip_lookup;
uint8_t h_table[H_SIZE] __attribute__((aligned(64)));
struct work_queue_t {
char *path;
struct work_queue_t *next;
};
typedef struct work_queue_t work_queue_t;
work_queue_t *work_queue;
work_queue_t *work_queue_tail;
int done_adding_files;
pthread_cond_t files_ready;
pthread_mutex_t stats_mtx;
pthread_mutex_t work_queue_mtx;
/* For symlink loop detection */
#define SYMLOOP_ERROR (-1)
#define SYMLOOP_OK (0)
#define SYMLOOP_LOOP (1)
typedef struct {
dev_t dev;
ino_t ino;
} dirkey_t;
typedef struct {
dirkey_t key;
UT_hash_handle hh;
} symdir_t;
symdir_t *symhash;
void search_buf(const char *buf, const size_t buf_len,
const char *dir_full_path);
void search_stream(FILE *stream, const char *path);
void search_file(const char *file_full_path);
void *search_file_worker(void *i);
void search_dir(ignores *ig, const char *base_path, const char *path, const int depth, dev_t original_dev);
#endif

971
third-party/libag/include/uthash.h vendored Normal file
View File

@ -0,0 +1,971 @@
/*
Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UTHASH_H
#define UTHASH_H
#include <stddef.h> /* ptrdiff_t */
#include <stdlib.h> /* exit() */
#include <string.h> /* memcmp,strlen */
/* These macros use decltype or the earlier __typeof GNU extension.
As decltype is only available in newer compilers (VS2010 or gcc 4.3+
when compiling c++ source) this code uses whatever method is needed
or, for VS2008 where neither is available, uses casting workarounds. */
#if defined(_MSC_VER) /* MS compiler */
#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
#define DECLTYPE(x) (decltype(x))
#else /* VS2008 or older (or VS2010 in C mode) */
#define NO_DECLTYPE
#define DECLTYPE(x)
#endif
#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__)
#define NO_DECLTYPE
#define DECLTYPE(x)
#else /* GNU, Sun and other compilers */
#define DECLTYPE(x) (__typeof(x))
#endif
#ifdef NO_DECLTYPE
#define DECLTYPE_ASSIGN(dst, src) \
do { \
char **_da_dst = (char **)(&(dst)); \
*_da_dst = (char *)(src); \
} while (0)
#else
#define DECLTYPE_ASSIGN(dst, src) \
do { \
(dst) = DECLTYPE(dst)(src); \
} while (0)
#endif
/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1600
#include <stdint.h>
#elif defined(__WATCOMC__)
#include <stdint.h>
#else
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#endif
#else
#include <stdint.h>
#endif
#define UTHASH_VERSION 1.9.9
#ifndef uthash_fatal
#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
#endif
#ifndef uthash_malloc
#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
#endif
#ifndef uthash_free
#define uthash_free(ptr, sz) free(ptr) /* free fcn */
#endif
#ifndef uthash_noexpand_fyi
#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
#endif
#ifndef uthash_expand_fyi
#define uthash_expand_fyi(tbl) /* can be defined to log expands */
#endif
/* initial number of buckets */
#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
/* calculate the element whose hash handle address is hhe */
#define ELMT_FROM_HH(tbl, hhp) ((void *)(((char *)(hhp)) - ((tbl)->hho)))
#define HASH_FIND(hh, head, keyptr, keylen, out) \
do { \
unsigned _hf_bkt, _hf_hashv; \
out = NULL; \
if (head) { \
HASH_FCN(keyptr, keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[_hf_bkt], keyptr, keylen, out); \
} \
} \
} while (0)
#ifdef HASH_BLOOM
#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN / 8) + ((HASH_BLOOM_BITLEN % 8) ? 1 : 0)
#define HASH_BLOOM_MAKE(tbl) \
do { \
(tbl)->bloom_nbits = HASH_BLOOM; \
(tbl)->bloom_bv = (uint8_t *)uthash_malloc(HASH_BLOOM_BYTELEN); \
if (!((tbl)->bloom_bv)) { \
uthash_fatal("out of memory"); \
} \
memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
(tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
} while (0)
#define HASH_BLOOM_FREE(tbl) \
do { \
uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
} while (0)
#define HASH_BLOOM_BITSET(bv, idx) (bv[(idx) / 8] |= (1U << ((idx) % 8)))
#define HASH_BLOOM_BITTEST(bv, idx) (bv[(idx) / 8] & (1U << ((idx) % 8)))
#define HASH_BLOOM_ADD(tbl, hashv) \
HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
#define HASH_BLOOM_TEST(tbl, hashv) \
HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
#else
#define HASH_BLOOM_MAKE(tbl)
#define HASH_BLOOM_FREE(tbl)
#define HASH_BLOOM_ADD(tbl, hashv)
#define HASH_BLOOM_TEST(tbl, hashv) (1)
#define HASH_BLOOM_BYTELEN 0
#endif
#define HASH_MAKE_TABLE(hh, head) \
do { \
(head)->hh.tbl = (UT_hash_table *)uthash_malloc(sizeof(UT_hash_table)); \
if (!((head)->hh.tbl)) { \
uthash_fatal("out of memory"); \
} \
memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
(head)->hh.tbl->tail = &((head)->hh); \
(head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
(head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
(head)->hh.tbl->hho = (char *)(&(head)->hh) - (char *)(head); \
(head)->hh.tbl->buckets = (UT_hash_bucket *)uthash_malloc(HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
if (!(head)->hh.tbl->buckets) { \
uthash_fatal("out of memory"); \
} \
memset((head)->hh.tbl->buckets, 0, HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
HASH_BLOOM_MAKE((head)->hh.tbl); \
(head)->hh.tbl->signature = HASH_SIGNATURE; \
} while (0)
#define HASH_ADD(hh, head, fieldname, keylen_in, add) \
HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add)
#define HASH_REPLACE(hh, head, fieldname, keylen_in, add, replaced) \
do { \
replaced = NULL; \
HASH_FIND(hh, head, &((add)->fieldname), keylen_in, replaced); \
if (replaced != NULL) { \
HASH_DELETE(hh, head, replaced); \
}; \
HASH_ADD(hh, head, fieldname, keylen_in, add); \
} while (0)
#define HASH_ADD_KEYPTR(hh, head, keyptr, keylen_in, add) \
do { \
unsigned _ha_bkt; \
(add)->hh.next = NULL; \
(add)->hh.key = (char *)(keyptr); \
(add)->hh.keylen = (unsigned)(keylen_in); \
if (!(head)) { \
head = (add); \
(head)->hh.prev = NULL; \
HASH_MAKE_TABLE(hh, head); \
} else { \
(head)->hh.tbl->tail->next = (add); \
(add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
(head)->hh.tbl->tail = &((add)->hh); \
} \
(head)->hh.tbl->num_items++; \
(add)->hh.tbl = (head)->hh.tbl; \
HASH_FCN(keyptr, keylen_in, (head)->hh.tbl->num_buckets, (add)->hh.hashv, _ha_bkt); \
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \
HASH_BLOOM_ADD((head)->hh.tbl, (add)->hh.hashv); \
HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
HASH_FSCK(hh, head); \
} while (0)
#define HASH_TO_BKT(hashv, num_bkts, bkt) \
do { \
bkt = ((hashv) & (num_bkts - 1)); \
} while (0)
/* delete "delptr" from the hash table.
* "the usual" patch-up process for the app-order doubly-linked-list.
* The use of _hd_hh_del below deserves special explanation.
* These used to be expressed using (delptr) but that led to a bug
* if someone used the same symbol for the head and deletee, like
* HASH_DELETE(hh,users,users);
* We want that to work, but by changing the head (users) below
* we were forfeiting our ability to further refer to the deletee (users)
* in the patch-up process. Solution: use scratch space to
* copy the deletee pointer, then the latter references are via that
* scratch pointer rather than through the repointed (users) symbol.
*/
#define HASH_DELETE(hh, head, delptr) \
do { \
unsigned _hd_bkt; \
struct UT_hash_handle *_hd_hh_del; \
if (((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL)) { \
uthash_free((head)->hh.tbl->buckets, (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
head = NULL; \
} else { \
_hd_hh_del = &((delptr)->hh); \
if ((delptr) == ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail)) { \
(head)->hh.tbl->tail = (UT_hash_handle *)((ptrdiff_t)((delptr)->hh.prev) + (head)->hh.tbl->hho); \
} \
if ((delptr)->hh.prev) { \
((UT_hash_handle *)((ptrdiff_t)((delptr)->hh.prev) + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \
} else { \
DECLTYPE_ASSIGN(head, (delptr)->hh.next); \
} \
if (_hd_hh_del->next) { \
((UT_hash_handle *)((ptrdiff_t)_hd_hh_del->next + (head)->hh.tbl->hho))->prev = _hd_hh_del->prev; \
} \
HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
HASH_DEL_IN_BKT(hh, (head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
(head)->hh.tbl->num_items--; \
} \
HASH_FSCK(hh, head); \
} while (0)
/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
#define HASH_FIND_STR(head, findstr, out) \
HASH_FIND(hh, head, findstr, strlen(findstr), out)
#define HASH_ADD_STR(head, strfield, add) \
HASH_ADD(hh, head, strfield[0], strlen(add->strfield), add)
#define HASH_REPLACE_STR(head, strfield, add, replaced) \
HASH_REPLACE(hh, head, strfield[0], strlen(add->strfield), add, replaced)
#define HASH_FIND_INT(head, findint, out) \
HASH_FIND(hh, head, findint, sizeof(int), out)
#define HASH_ADD_INT(head, intfield, add) \
HASH_ADD(hh, head, intfield, sizeof(int), add)
#define HASH_REPLACE_INT(head, intfield, add, replaced) \
HASH_REPLACE(hh, head, intfield, sizeof(int), add, replaced)
#define HASH_FIND_PTR(head, findptr, out) \
HASH_FIND(hh, head, findptr, sizeof(void *), out)
#define HASH_ADD_PTR(head, ptrfield, add) \
HASH_ADD(hh, head, ptrfield, sizeof(void *), add)
#define HASH_REPLACE_PTR(head, ptrfield, add, replaced) \
HASH_REPLACE(hh, head, ptrfield, sizeof(void *), add, replaced)
#define HASH_DEL(head, delptr) \
HASH_DELETE(hh, head, delptr)
/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
* This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
*/
#ifdef HASH_DEBUG
#define HASH_OOPS(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
exit(-1); \
} while (0)
#define HASH_FSCK(hh, head) \
do { \
unsigned _bkt_i; \
unsigned _count, _bkt_count; \
char *_prev; \
struct UT_hash_handle *_thh; \
if (head) { \
_count = 0; \
for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
_bkt_count = 0; \
_thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
_prev = NULL; \
while (_thh) { \
if (_prev != (char *)(_thh->hh_prev)) { \
HASH_OOPS("invalid hh_prev %p, actual %p\n", _thh->hh_prev, _prev); \
} \
_bkt_count++; \
_prev = (char *)(_thh); \
_thh = _thh->hh_next; \
} \
_count += _bkt_count; \
if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
HASH_OOPS("invalid bucket count %d, actual %d\n", (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
} \
} \
if (_count != (head)->hh.tbl->num_items) { \
HASH_OOPS("invalid hh item count %d, actual %d\n", (head)->hh.tbl->num_items, _count); \
} \
/* traverse hh in app order; check next/prev integrity, count */ \
_count = 0; \
_prev = NULL; \
_thh = &(head)->hh; \
while (_thh) { \
_count++; \
if (_prev != (char *)(_thh->prev)) { \
HASH_OOPS("invalid prev %p, actual %p\n", _thh->prev, _prev); \
} \
_prev = (char *)ELMT_FROM_HH((head)->hh.tbl, _thh); \
_thh = (_thh->next ? (UT_hash_handle *)((char *)(_thh->next) + (head)->hh.tbl->hho) : NULL); \
} \
if (_count != (head)->hh.tbl->num_items) { \
HASH_OOPS("invalid app item count %d, actual %d\n", (head)->hh.tbl->num_items, _count); \
} \
} \
} while (0)
#else
#define HASH_FSCK(hh, head)
#endif
/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
* the descriptor to which this macro is defined for tuning the hash function.
* The app can #include <unistd.h> to get the prototype for write(2). */
#ifdef HASH_EMIT_KEYS
#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen) \
do { \
unsigned _klen = fieldlen; \
write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
write(HASH_EMIT_KEYS, keyptr, fieldlen); \
} while (0)
#else
#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen)
#endif
/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
#ifdef HASH_FUNCTION
#define HASH_FCN HASH_FUNCTION
#else
#define HASH_FCN HASH_JEN
#endif
/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
#define HASH_BER(key, keylen, num_bkts, hashv, bkt) \
do { \
unsigned _hb_keylen = keylen; \
char *_hb_key = (char *)(key); \
(hashv) = 0; \
while (_hb_keylen--) { \
(hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \
} \
bkt = (hashv) & (num_bkts - 1); \
} while (0)
/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
#define HASH_SAX(key, keylen, num_bkts, hashv, bkt) \
do { \
unsigned _sx_i; \
char *_hs_key = (char *)(key); \
hashv = 0; \
for (_sx_i = 0; _sx_i < keylen; _sx_i++) \
hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
bkt = hashv & (num_bkts - 1); \
} while (0)
/* FNV-1a variation */
#define HASH_FNV(key, keylen, num_bkts, hashv, bkt) \
do { \
unsigned _fn_i; \
char *_hf_key = (char *)(key); \
hashv = 2166136261UL; \
for (_fn_i = 0; _fn_i < keylen; _fn_i++) \
hashv = hashv ^ _hf_key[_fn_i]; \
hashv = hashv * 16777619; \
bkt = hashv & (num_bkts - 1); \
} while (0)
#define HASH_OAT(key, keylen, num_bkts, hashv, bkt) \
do { \
unsigned _ho_i; \
char *_ho_key = (char *)(key); \
hashv = 0; \
for (_ho_i = 0; _ho_i < keylen; _ho_i++) { \
hashv += _ho_key[_ho_i]; \
hashv += (hashv << 10); \
hashv ^= (hashv >> 6); \
} \
hashv += (hashv << 3); \
hashv ^= (hashv >> 11); \
hashv += (hashv << 15); \
bkt = hashv & (num_bkts - 1); \
} while (0)
#define HASH_JEN_MIX(a, b, c) \
do { \
a -= b; \
a -= c; \
a ^= (c >> 13); \
b -= c; \
b -= a; \
b ^= (a << 8); \
c -= a; \
c -= b; \
c ^= (b >> 13); \
a -= b; \
a -= c; \
a ^= (c >> 12); \
b -= c; \
b -= a; \
b ^= (a << 16); \
c -= a; \
c -= b; \
c ^= (b >> 5); \
a -= b; \
a -= c; \
a ^= (c >> 3); \
b -= c; \
b -= a; \
b ^= (a << 10); \
c -= a; \
c -= b; \
c ^= (b >> 15); \
} while (0)
#define HASH_JEN(key, keylen, num_bkts, hashv, bkt) \
do { \
unsigned _hj_i, _hj_j, _hj_k; \
unsigned char *_hj_key = (unsigned char *)(key); \
hashv = 0xfeedbeef; \
_hj_i = _hj_j = 0x9e3779b9; \
_hj_k = (unsigned)(keylen); \
while (_hj_k >= 12) { \
_hj_i += (_hj_key[0] + ((unsigned)_hj_key[1] << 8) + ((unsigned)_hj_key[2] << 16) + ((unsigned)_hj_key[3] << 24)); \
_hj_j += (_hj_key[4] + ((unsigned)_hj_key[5] << 8) + ((unsigned)_hj_key[6] << 16) + ((unsigned)_hj_key[7] << 24)); \
hashv += (_hj_key[8] + ((unsigned)_hj_key[9] << 8) + ((unsigned)_hj_key[10] << 16) + ((unsigned)_hj_key[11] << 24)); \
\
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
\
_hj_key += 12; \
_hj_k -= 12; \
} \
hashv += keylen; \
switch (_hj_k) { \
case 11: \
hashv += ((unsigned)_hj_key[10] << 24); \
/* fall through */ \
case 10: \
hashv += ((unsigned)_hj_key[9] << 16); \
/* fall through */ \
case 9: \
hashv += ((unsigned)_hj_key[8] << 8); \
/* fall through */ \
case 8: \
_hj_j += ((unsigned)_hj_key[7] << 24); \
/* fall through */ \
case 7: \
_hj_j += ((unsigned)_hj_key[6] << 16); \
/* fall through */ \
case 6: \
_hj_j += ((unsigned)_hj_key[5] << 8); \
/* fall through */ \
case 5: \
_hj_j += _hj_key[4]; \
/* fall through */ \
case 4: \
_hj_i += ((unsigned)_hj_key[3] << 24); \
/* fall through */ \
case 3: \
_hj_i += ((unsigned)_hj_key[2] << 16); \
/* fall through */ \
case 2: \
_hj_i += ((unsigned)_hj_key[1] << 8); \
/* fall through */ \
case 1: \
_hj_i += _hj_key[0]; \
} \
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
bkt = hashv & (num_bkts - 1); \
} while (0)
/* The Paul Hsieh hash function */
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__)
#define get16bits(d) (*((const uint16_t *)(d)))
#endif
#if !defined(get16bits)
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) + (uint32_t)(((const uint8_t *)(d))[0]))
#endif
#define HASH_SFH(key, keylen, num_bkts, hashv, bkt) \
do { \
unsigned char *_sfh_key = (unsigned char *)(key); \
uint32_t _sfh_tmp, _sfh_len = keylen; \
\
int _sfh_rem = _sfh_len & 3; \
_sfh_len >>= 2; \
hashv = 0xcafebabe; \
\
/* Main loop */ \
for (; _sfh_len > 0; _sfh_len--) { \
hashv += get16bits(_sfh_key); \
_sfh_tmp = (uint32_t)(get16bits(_sfh_key + 2)) << 11 ^ hashv; \
hashv = (hashv << 16) ^ _sfh_tmp; \
_sfh_key += 2 * sizeof(uint16_t); \
hashv += hashv >> 11; \
} \
\
/* Handle end cases */ \
switch (_sfh_rem) { \
case 3: \
hashv += get16bits(_sfh_key); \
hashv ^= hashv << 16; \
hashv ^= (uint32_t)(_sfh_key[sizeof(uint16_t)] << 18); \
hashv += hashv >> 11; \
break; \
case 2: \
hashv += get16bits(_sfh_key); \
hashv ^= hashv << 11; \
hashv += hashv >> 17; \
break; \
case 1: \
hashv += *_sfh_key; \
hashv ^= hashv << 10; \
hashv += hashv >> 1; \
} \
\
/* Force "avalanching" of final 127 bits */ \
hashv ^= hashv << 3; \
hashv += hashv >> 5; \
hashv ^= hashv << 4; \
hashv += hashv >> 17; \
hashv ^= hashv << 25; \
hashv += hashv >> 6; \
bkt = hashv & (num_bkts - 1); \
} while (0)
#ifdef HASH_USING_NO_STRICT_ALIASING
/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
* For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
* MurmurHash uses the faster approach only on CPU's where we know it's safe.
*
* Note the preprocessor built-in defines can be emitted using:
*
* gcc -m64 -dM -E - < /dev/null (on gcc)
* cc -## a.c (where a.c is a simple test file) (Sun Studio)
*/
#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86))
#define MUR_GETBLOCK(p, i) p[i]
#else /* non intel */
#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
#define WP(p) ((uint32_t *)((unsigned long)(p) & ~3UL))
#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
#define MUR_THREE_ONE(p) ((((*WP(p)) & 0x00ffffff) << 8) | (((*(WP(p) + 1)) & 0xff000000) >> 24))
#define MUR_TWO_TWO(p) ((((*WP(p)) & 0x0000ffff) << 16) | (((*(WP(p) + 1)) & 0xffff0000) >> 16))
#define MUR_ONE_THREE(p) ((((*WP(p)) & 0x000000ff) << 24) | (((*(WP(p) + 1)) & 0xffffff00) >> 8))
#else /* assume little endian non-intel */
#define MUR_THREE_ONE(p) ((((*WP(p)) & 0xffffff00) >> 8) | (((*(WP(p) + 1)) & 0x000000ff) << 24))
#define MUR_TWO_TWO(p) ((((*WP(p)) & 0xffff0000) >> 16) | (((*(WP(p) + 1)) & 0x0000ffff) << 16))
#define MUR_ONE_THREE(p) ((((*WP(p)) & 0xff000000) >> 24) | (((*(WP(p) + 1)) & 0x00ffffff) << 8))
#endif
#define MUR_GETBLOCK(p, i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : MUR_ONE_THREE(p))))
#endif
#define MUR_ROTL32(x, r) (((x) << (r)) | ((x) >> (32 - (r))))
#define MUR_FMIX(_h) \
do { \
_h ^= _h >> 16; \
_h *= 0x85ebca6b; \
_h ^= _h >> 13; \
_h *= 0xc2b2ae35l; \
_h ^= _h >> 16; \
} while (0)
#define HASH_MUR(key, keylen, num_bkts, hashv, bkt) \
do { \
const uint8_t *_mur_data = (const uint8_t *)(key); \
const int _mur_nblocks = (keylen) / 4; \
uint32_t _mur_h1 = 0xf88D5353; \
uint32_t _mur_c1 = 0xcc9e2d51; \
uint32_t _mur_c2 = 0x1b873593; \
uint32_t _mur_k1 = 0; \
const uint8_t *_mur_tail; \
const uint32_t *_mur_blocks = (const uint32_t *)(_mur_data + _mur_nblocks * 4); \
int _mur_i; \
for (_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \
_mur_k1 = MUR_GETBLOCK(_mur_blocks, _mur_i); \
_mur_k1 *= _mur_c1; \
_mur_k1 = MUR_ROTL32(_mur_k1, 15); \
_mur_k1 *= _mur_c2; \
\
_mur_h1 ^= _mur_k1; \
_mur_h1 = MUR_ROTL32(_mur_h1, 13); \
_mur_h1 = _mur_h1 * 5 + 0xe6546b64; \
} \
_mur_tail = (const uint8_t *)(_mur_data + _mur_nblocks * 4); \
_mur_k1 = 0; \
switch (keylen & 3) { \
case 3: \
_mur_k1 ^= _mur_tail[2] << 16; \
case 2: \
_mur_k1 ^= _mur_tail[1] << 8; \
case 1: \
_mur_k1 ^= _mur_tail[0]; \
_mur_k1 *= _mur_c1; \
_mur_k1 = MUR_ROTL32(_mur_k1, 15); \
_mur_k1 *= _mur_c2; \
_mur_h1 ^= _mur_k1; \
} \
_mur_h1 ^= (keylen); \
MUR_FMIX(_mur_h1); \
hashv = _mur_h1; \
bkt = hashv & (num_bkts - 1); \
} while (0)
#endif /* HASH_USING_NO_STRICT_ALIASING */
/* key comparison function; return 0 if keys equal */
#define HASH_KEYCMP(a, b, len) memcmp(a, b, len)
/* iterate over items in a known bucket to find desired item */
#define HASH_FIND_IN_BKT(tbl, hh, head, keyptr, keylen_in, out) \
do { \
if (head.hh_head) \
DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, head.hh_head)); \
else \
out = NULL; \
while (out) { \
if ((out)->hh.keylen == keylen_in) { \
if ((HASH_KEYCMP((out)->hh.key, keyptr, keylen_in)) == 0) \
break; \
} \
if ((out)->hh.hh_next) \
DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \
else \
out = NULL; \
} \
} while (0)
/* add an item to a bucket */
#define HASH_ADD_TO_BKT(head, addhh) \
do { \
head.count++; \
(addhh)->hh_next = head.hh_head; \
(addhh)->hh_prev = NULL; \
if (head.hh_head) { \
(head).hh_head->hh_prev = (addhh); \
} \
(head).hh_head = addhh; \
if (head.count >= ((head.expand_mult + 1) * HASH_BKT_CAPACITY_THRESH) && (addhh)->tbl->noexpand != 1) { \
HASH_EXPAND_BUCKETS((addhh)->tbl); \
} \
} while (0)
/* remove an item from a given bucket */
#define HASH_DEL_IN_BKT(hh, head, hh_del) \
(head).count--; \
if ((head).hh_head == hh_del) { \
(head).hh_head = hh_del->hh_next; \
} \
if (hh_del->hh_prev) { \
hh_del->hh_prev->hh_next = hh_del->hh_next; \
} \
if (hh_del->hh_next) { \
hh_del->hh_next->hh_prev = hh_del->hh_prev; \
}
/* Bucket expansion has the effect of doubling the number of buckets
* and redistributing the items into the new buckets. Ideally the
* items will distribute more or less evenly into the new buckets
* (the extent to which this is true is a measure of the quality of
* the hash function as it applies to the key domain).
*
* With the items distributed into more buckets, the chain length
* (item count) in each bucket is reduced. Thus by expanding buckets
* the hash keeps a bound on the chain length. This bounded chain
* length is the essence of how a hash provides constant time lookup.
*
* The calculation of tbl->ideal_chain_maxlen below deserves some
* explanation. First, keep in mind that we're calculating the ideal
* maximum chain length based on the *new* (doubled) bucket count.
* In fractions this is just n/b (n=number of items,b=new num buckets).
* Since the ideal chain length is an integer, we want to calculate
* ceil(n/b). We don't depend on floating point arithmetic in this
* hash, so to calculate ceil(n/b) with integers we could write
*
* ceil(n/b) = (n/b) + ((n%b)?1:0)
*
* and in fact a previous version of this hash did just that.
* But now we have improved things a bit by recognizing that b is
* always a power of two. We keep its base 2 log handy (call it lb),
* so now we can write this with a bit shift and logical AND:
*
* ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
*
*/
#define HASH_EXPAND_BUCKETS(tbl) \
do { \
unsigned _he_bkt; \
unsigned _he_bkt_i; \
struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
_he_new_buckets = (UT_hash_bucket *)uthash_malloc(2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
if (!_he_new_buckets) { \
uthash_fatal("out of memory"); \
} \
memset(_he_new_buckets, 0, 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
tbl->ideal_chain_maxlen = (tbl->num_items >> (tbl->log2_num_buckets + 1)) + ((tbl->num_items & ((tbl->num_buckets * 2) - 1)) ? 1 : 0); \
tbl->nonideal_items = 0; \
for (_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) { \
_he_thh = tbl->buckets[_he_bkt_i].hh_head; \
while (_he_thh) { \
_he_hh_nxt = _he_thh->hh_next; \
HASH_TO_BKT(_he_thh->hashv, tbl->num_buckets * 2, _he_bkt); \
_he_newbkt = &(_he_new_buckets[_he_bkt]); \
if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \
tbl->nonideal_items++; \
_he_newbkt->expand_mult = _he_newbkt->count / tbl->ideal_chain_maxlen; \
} \
_he_thh->hh_prev = NULL; \
_he_thh->hh_next = _he_newbkt->hh_head; \
if (_he_newbkt->hh_head) \
_he_newbkt->hh_head->hh_prev = _he_thh; \
_he_newbkt->hh_head = _he_thh; \
_he_thh = _he_hh_nxt; \
} \
} \
uthash_free(tbl->buckets, tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
tbl->num_buckets *= 2; \
tbl->log2_num_buckets++; \
tbl->buckets = _he_new_buckets; \
tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? (tbl->ineff_expands + 1) : 0; \
if (tbl->ineff_expands > 1) { \
tbl->noexpand = 1; \
uthash_noexpand_fyi(tbl); \
} \
uthash_expand_fyi(tbl); \
} while (0)
/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
/* Note that HASH_SORT assumes the hash handle name to be hh.
* HASH_SRT was added to allow the hash handle name to be passed in. */
#define HASH_SORT(head, cmpfcn) HASH_SRT(hh, head, cmpfcn)
#define HASH_SRT(hh, head, cmpfcn) \
do { \
unsigned _hs_i; \
unsigned _hs_looping, _hs_nmerges, _hs_insize, _hs_psize, _hs_qsize; \
struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
if (head) { \
_hs_insize = 1; \
_hs_looping = 1; \
_hs_list = &((head)->hh); \
while (_hs_looping) { \
_hs_p = _hs_list; \
_hs_list = NULL; \
_hs_tail = NULL; \
_hs_nmerges = 0; \
while (_hs_p) { \
_hs_nmerges++; \
_hs_q = _hs_p; \
_hs_psize = 0; \
for (_hs_i = 0; _hs_i < _hs_insize; _hs_i++) { \
_hs_psize++; \
_hs_q = (UT_hash_handle *)((_hs_q->next) ? ((void *)((char *)(_hs_q->next) + (head)->hh.tbl->hho)) : NULL); \
if (!(_hs_q)) \
break; \
} \
_hs_qsize = _hs_insize; \
while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q)) { \
if (_hs_psize == 0) { \
_hs_e = _hs_q; \
_hs_q = (UT_hash_handle *)((_hs_q->next) ? ((void *)((char *)(_hs_q->next) + (head)->hh.tbl->hho)) : NULL); \
_hs_qsize--; \
} else if ((_hs_qsize == 0) || !(_hs_q)) { \
_hs_e = _hs_p; \
if (_hs_p) { \
_hs_p = (UT_hash_handle *)((_hs_p->next) ? ((void *)((char *)(_hs_p->next) + (head)->hh.tbl->hho)) : NULL); \
} \
_hs_psize--; \
} else if ((cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)))) <= 0) { \
_hs_e = _hs_p; \
if (_hs_p) { \
_hs_p = (UT_hash_handle *)((_hs_p->next) ? ((void *)((char *)(_hs_p->next) + (head)->hh.tbl->hho)) : NULL); \
} \
_hs_psize--; \
} else { \
_hs_e = _hs_q; \
_hs_q = (UT_hash_handle *)((_hs_q->next) ? ((void *)((char *)(_hs_q->next) + (head)->hh.tbl->hho)) : NULL); \
_hs_qsize--; \
} \
if (_hs_tail) { \
_hs_tail->next = ((_hs_e) ? ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \
} else { \
_hs_list = _hs_e; \
} \
if (_hs_e) { \
_hs_e->prev = ((_hs_tail) ? ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \
} \
_hs_tail = _hs_e; \
} \
_hs_p = _hs_q; \
} \
if (_hs_tail) { \
_hs_tail->next = NULL; \
} \
if (_hs_nmerges <= 1) { \
_hs_looping = 0; \
(head)->hh.tbl->tail = _hs_tail; \
DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
} \
_hs_insize *= 2; \
} \
HASH_FSCK(hh, head); \
} \
} while (0)
/* This function selects items from one hash into another hash.
* The end result is that the selected items have dual presence
* in both hashes. There is no copy of the items made; rather
* they are added into the new hash through a secondary hash
* hash handle that must be present in the structure. */
#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
do { \
unsigned _src_bkt, _dst_bkt; \
void *_last_elt = NULL, *_elt; \
UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh = NULL; \
ptrdiff_t _dst_hho = ((char *)(&(dst)->hh_dst) - (char *)(dst)); \
if (src) { \
for (_src_bkt = 0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; _src_hh; _src_hh = _src_hh->hh_next) { \
_elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
if (cond(_elt)) { \
_dst_hh = (UT_hash_handle *)(((char *)_elt) + _dst_hho); \
_dst_hh->key = _src_hh->key; \
_dst_hh->keylen = _src_hh->keylen; \
_dst_hh->hashv = _src_hh->hashv; \
_dst_hh->prev = _last_elt; \
_dst_hh->next = NULL; \
if (_last_elt_hh) { \
_last_elt_hh->next = _elt; \
} \
if (!dst) { \
DECLTYPE_ASSIGN(dst, _elt); \
HASH_MAKE_TABLE(hh_dst, dst); \
} else { \
_dst_hh->tbl = (dst)->hh_dst.tbl; \
} \
HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], _dst_hh); \
(dst)->hh_dst.tbl->num_items++; \
_last_elt = _elt; \
_last_elt_hh = _dst_hh; \
} \
} \
} \
} \
HASH_FSCK(hh_dst, dst); \
} while (0)
#define HASH_CLEAR(hh, head) \
do { \
if (head) { \
uthash_free((head)->hh.tbl->buckets, (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
(head) = NULL; \
} \
} while (0)
#define HASH_OVERHEAD(hh, head) \
(size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
(sizeof(UT_hash_table)) + \
(HASH_BLOOM_BYTELEN)))
#ifdef NO_DECLTYPE
#define HASH_ITER(hh, head, el, tmp) for ((el) = (head), (*(char **)(&(tmp))) = (char *)((head) ? (head)->hh.next : NULL); \
el; (el) = (tmp), (*(char **)(&(tmp))) = (char *)((tmp) ? (tmp)->hh.next : NULL))
#else
#define HASH_ITER(hh, head, el, tmp) for ((el) = (head), (tmp) = DECLTYPE(el)((head) ? (head)->hh.next : NULL); \
el; (el) = (tmp), (tmp) = DECLTYPE(el)((tmp) ? (tmp)->hh.next : NULL))
#endif
/* obtain a count of items in the hash */
#define HASH_COUNT(head) HASH_CNT(hh, head)
#define HASH_CNT(hh, head) ((head) ? ((head)->hh.tbl->num_items) : 0)
typedef struct UT_hash_bucket {
struct UT_hash_handle *hh_head;
unsigned count;
/* expand_mult is normally set to 0. In this situation, the max chain length
* threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
* the bucket's chain exceeds this length, bucket expansion is triggered).
* However, setting expand_mult to a non-zero value delays bucket expansion
* (that would be triggered by additions to this particular bucket)
* until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
* (The multiplier is simply expand_mult+1). The whole idea of this
* multiplier is to reduce bucket expansions, since they are expensive, in
* situations where we know that a particular bucket tends to be overused.
* It is better to let its chain length grow to a longer yet-still-bounded
* value, than to do an O(n) bucket expansion too often.
*/
unsigned expand_mult;
} UT_hash_bucket;
/* random signature used only to find hash tables in external analysis */
#define HASH_SIGNATURE 0xa0111fe1
#define HASH_BLOOM_SIGNATURE 0xb12220f2
typedef struct UT_hash_table {
UT_hash_bucket *buckets;
unsigned num_buckets, log2_num_buckets;
unsigned num_items;
struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
/* in an ideal situation (all buckets used equally), no bucket would have
* more than ceil(#items/#buckets) items. that's the ideal chain length. */
unsigned ideal_chain_maxlen;
/* nonideal_items is the number of items in the hash whose chain position
* exceeds the ideal chain maxlen. these items pay the penalty for an uneven
* hash distribution; reaching them in a chain traversal takes >ideal steps */
unsigned nonideal_items;
/* ineffective expands occur when a bucket doubling was performed, but
* afterward, more than half the items in the hash had nonideal chain
* positions. If this happens on two consecutive expansions we inhibit any
* further expansion, as it's not helping; this happens when the hash
* function isn't a good fit for the key domain. When expansion is inhibited
* the hash will still work, albeit no longer in constant time. */
unsigned ineff_expands, noexpand;
uint32_t signature; /* used only to find hash tables in external analysis */
#ifdef HASH_BLOOM
uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
uint8_t *bloom_bv;
char bloom_nbits;
#endif
} UT_hash_table;
typedef struct UT_hash_handle {
struct UT_hash_table *tbl;
void *prev; /* prev element in app order */
void *next; /* next element in app order */
struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
struct UT_hash_handle *hh_next; /* next hh in bucket order */
void *key; /* ptr to enclosing struct's key */
unsigned keylen; /* enclosing struct's key len */
unsigned hashv; /* result of hash-fcn(key) */
} UT_hash_handle;
#endif /* UTHASH_H */

119
third-party/libag/include/util.h vendored Normal file
View File

@ -0,0 +1,119 @@
#ifndef UTIL_H
#define UTIL_H
#include <dirent.h>
#include <pcre.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include "config.h"
#include "log.h"
#include "options.h"
FILE *out_fd;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define H_SIZE (64 * 1024)
#ifdef __clang__
#define NO_SANITIZE_ALIGNMENT __attribute__((no_sanitize("alignment")))
#else
#define NO_SANITIZE_ALIGNMENT
#endif
void *ag_malloc(size_t size);
void *ag_realloc(void *ptr, size_t size);
void *ag_calloc(size_t nelem, size_t elsize);
char *ag_strdup(const char *s);
char *ag_strndup(const char *s, size_t size);
typedef struct {
size_t start; /* Byte at which the match starts */
size_t end; /* and where it ends */
} match_t;
typedef struct {
size_t total_bytes;
size_t total_files;
size_t total_matches;
size_t total_file_matches;
struct timeval time_start;
struct timeval time_end;
} ag_stats;
ag_stats stats;
/* Union to translate between chars and words without violating strict aliasing */
typedef union {
char as_chars[sizeof(uint16_t)];
uint16_t as_word;
} word_t;
void free_strings(char **strs, const size_t strs_len);
void generate_alpha_skip(const char *find, size_t f_len, size_t skip_lookup[], const int case_sensitive);
int is_prefix(const char *s, const size_t s_len, const size_t pos, const int case_sensitive);
size_t suffix_len(const char *s, const size_t s_len, const size_t pos, const int case_sensitive);
void generate_find_skip(const char *find, const size_t f_len, size_t **skip_lookup, const int case_sensitive);
void generate_hash(const char *find, const size_t f_len, uint8_t *H, const int case_sensitive);
/* max is already defined on spec-violating compilers such as MinGW */
size_t ag_max(size_t a, size_t b);
size_t ag_min(size_t a, size_t b);
const char *boyer_moore_strnstr(const char *s, const char *find, const size_t s_len, const size_t f_len,
const size_t alpha_skip_lookup[], const size_t *find_skip_lookup, const int case_insensitive);
const char *hash_strnstr(const char *s, const char *find, const size_t s_len, const size_t f_len, uint8_t *h_table, const int case_sensitive);
size_t invert_matches(const char *buf, const size_t buf_len, match_t matches[], size_t matches_len);
void realloc_matches(match_t **matches, size_t *matches_size, size_t matches_len);
void compile_study(pcre **re, pcre_extra **re_extra, char *q, const int pcre_opts, const int study_opts);
int is_binary(const void *buf, const size_t buf_len);
int is_regex(const char *query);
int is_fnmatch(const char *filename);
int binary_search(const char *needle, char **haystack, int start, int end);
void init_wordchar_table(void);
int is_wordchar(char ch);
int is_lowercase(const char *s);
int is_directory(const char *path, const struct dirent *d);
int is_symlink(const char *path, const struct dirent *d);
int is_named_pipe(const char *path, const struct dirent *d);
void die(const char *fmt, ...);
void ag_asprintf(char **ret, const char *fmt, ...);
ssize_t buf_getline(const char **line, const char *buf, const size_t buf_len, const size_t buf_offset);
#ifndef HAVE_FGETLN
char *fgetln(FILE *fp, size_t *lenp);
#endif
#ifndef HAVE_GETLINE
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
#endif
#ifndef HAVE_REALPATH
char *realpath(const char *path, char *resolved_path);
#endif
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dest, const char *src, size_t size);
#endif
#ifndef HAVE_VASPRINTF
int vasprintf(char **ret, const char *fmt, va_list args);
#endif
#endif

3
third-party/libag/lib/libag.a vendored Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:24c1ae7219e2309f7603913e01da2819d91d56ca62ea5263d647044172bc145c
size 118440

677
third-party/libpcre/include/pcre.h vendored Normal file
View File

@ -0,0 +1,677 @@
/*************************************************
* Perl-Compatible Regular Expressions *
*************************************************/
/* This is the public header file for the PCRE library, to be #included by
applications that call the PCRE functions.
Copyright (c) 1997-2014 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
#ifndef _PCRE_H
#define _PCRE_H
/* The current PCRE version information. */
#define PCRE_MAJOR 8
#define PCRE_MINOR 43
#define PCRE_PRERELEASE
#define PCRE_DATE 2019-02-23
/* When an application links to a PCRE DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE, the appropriate
export setting is defined in pcre_internal.h, which includes this file. So we
don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */
#if defined(_WIN32) && !defined(PCRE_STATIC)
# ifndef PCRE_EXP_DECL
# define PCRE_EXP_DECL extern __declspec(dllimport)
# endif
# ifdef __cplusplus
# ifndef PCRECPP_EXP_DECL
# define PCRECPP_EXP_DECL extern __declspec(dllimport)
# endif
# ifndef PCRECPP_EXP_DEFN
# define PCRECPP_EXP_DEFN __declspec(dllimport)
# endif
# endif
#endif
/* By default, we use the standard "extern" declarations. */
#ifndef PCRE_EXP_DECL
# ifdef __cplusplus
# define PCRE_EXP_DECL extern "C"
# else
# define PCRE_EXP_DECL extern
# endif
#endif
#ifdef __cplusplus
# ifndef PCRECPP_EXP_DECL
# define PCRECPP_EXP_DECL extern
# endif
# ifndef PCRECPP_EXP_DEFN
# define PCRECPP_EXP_DEFN
# endif
#endif
/* Have to include stdlib.h in order to ensure that size_t is defined;
it is needed here for malloc. */
#include <stdlib.h>
/* Allow for C++ users */
#ifdef __cplusplus
extern "C" {
#endif
/* Public options. Some are compile-time only, some are run-time only, and some
are both. Most of the compile-time options are saved with the compiled regex so
that they can be inspected during studying (and therefore JIT compiling). Note
that pcre_study() has its own set of options. Originally, all the options
defined here used distinct bits. However, almost all the bits in a 32-bit word
are now used, so in order to conserve them, option bits that were previously
only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may
also be used for compile-time options that affect only compiling and are not
relevant for studying or JIT compiling.
Some options for pcre_compile() change its behaviour but do not affect the
behaviour of the execution functions. Other options are passed through to the
execution functions and affect their behaviour, with or without affecting the
behaviour of pcre_compile().
Options that can be passed to pcre_compile() are tagged Cx below, with these
variants:
C1 Affects compile only
C2 Does not affect compile; affects exec, dfa_exec
C3 Affects compile, exec, dfa_exec
C4 Affects compile, exec, dfa_exec, study
C5 Affects compile, exec, study
Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged with
E and D, respectively. They take precedence over C3, C4, and C5 settings passed
from pcre_compile(). Those that are compatible with JIT execution are flagged
with J. */
#define PCRE_CASELESS 0x00000001 /* C1 */
#define PCRE_MULTILINE 0x00000002 /* C1 */
#define PCRE_DOTALL 0x00000004 /* C1 */
#define PCRE_EXTENDED 0x00000008 /* C1 */
#define PCRE_ANCHORED 0x00000010 /* C4 E D */
#define PCRE_DOLLAR_ENDONLY 0x00000020 /* C2 */
#define PCRE_EXTRA 0x00000040 /* C1 */
#define PCRE_NOTBOL 0x00000080 /* E D J */
#define PCRE_NOTEOL 0x00000100 /* E D J */
#define PCRE_UNGREEDY 0x00000200 /* C1 */
#define PCRE_NOTEMPTY 0x00000400 /* E D J */
#define PCRE_UTF8 0x00000800 /* C4 ) */
#define PCRE_UTF16 0x00000800 /* C4 ) Synonyms */
#define PCRE_UTF32 0x00000800 /* C4 ) */
#define PCRE_NO_AUTO_CAPTURE 0x00001000 /* C1 */
#define PCRE_NO_UTF8_CHECK 0x00002000 /* C1 E D J ) */
#define PCRE_NO_UTF16_CHECK 0x00002000 /* C1 E D J ) Synonyms */
#define PCRE_NO_UTF32_CHECK 0x00002000 /* C1 E D J ) */
#define PCRE_AUTO_CALLOUT 0x00004000 /* C1 */
#define PCRE_PARTIAL_SOFT 0x00008000 /* E D J ) Synonyms */
#define PCRE_PARTIAL 0x00008000 /* E D J ) */
/* This pair use the same bit. */
#define PCRE_NEVER_UTF 0x00010000 /* C1 ) Overlaid */
#define PCRE_DFA_SHORTEST 0x00010000 /* D ) Overlaid */
/* This pair use the same bit. */
#define PCRE_NO_AUTO_POSSESS 0x00020000 /* C1 ) Overlaid */
#define PCRE_DFA_RESTART 0x00020000 /* D ) Overlaid */
#define PCRE_FIRSTLINE 0x00040000 /* C3 */
#define PCRE_DUPNAMES 0x00080000 /* C1 */
#define PCRE_NEWLINE_CR 0x00100000 /* C3 E D */
#define PCRE_NEWLINE_LF 0x00200000 /* C3 E D */
#define PCRE_NEWLINE_CRLF 0x00300000 /* C3 E D */
#define PCRE_NEWLINE_ANY 0x00400000 /* C3 E D */
#define PCRE_NEWLINE_ANYCRLF 0x00500000 /* C3 E D */
#define PCRE_BSR_ANYCRLF 0x00800000 /* C3 E D */
#define PCRE_BSR_UNICODE 0x01000000 /* C3 E D */
#define PCRE_JAVASCRIPT_COMPAT 0x02000000 /* C5 */
#define PCRE_NO_START_OPTIMIZE 0x04000000 /* C2 E D ) Synonyms */
#define PCRE_NO_START_OPTIMISE 0x04000000 /* C2 E D ) */
#define PCRE_PARTIAL_HARD 0x08000000 /* E D J */
#define PCRE_NOTEMPTY_ATSTART 0x10000000 /* E D J */
#define PCRE_UCP 0x20000000 /* C3 */
/* Exec-time and get/set-time error codes */
#define PCRE_ERROR_NOMATCH (-1)
#define PCRE_ERROR_NULL (-2)
#define PCRE_ERROR_BADOPTION (-3)
#define PCRE_ERROR_BADMAGIC (-4)
#define PCRE_ERROR_UNKNOWN_OPCODE (-5)
#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */
#define PCRE_ERROR_NOMEMORY (-6)
#define PCRE_ERROR_NOSUBSTRING (-7)
#define PCRE_ERROR_MATCHLIMIT (-8)
#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */
#define PCRE_ERROR_BADUTF8 (-10) /* Same for 8/16/32 */
#define PCRE_ERROR_BADUTF16 (-10) /* Same for 8/16/32 */
#define PCRE_ERROR_BADUTF32 (-10) /* Same for 8/16/32 */
#define PCRE_ERROR_BADUTF8_OFFSET (-11) /* Same for 8/16 */
#define PCRE_ERROR_BADUTF16_OFFSET (-11) /* Same for 8/16 */
#define PCRE_ERROR_PARTIAL (-12)
#define PCRE_ERROR_BADPARTIAL (-13)
#define PCRE_ERROR_INTERNAL (-14)
#define PCRE_ERROR_BADCOUNT (-15)
#define PCRE_ERROR_DFA_UITEM (-16)
#define PCRE_ERROR_DFA_UCOND (-17)
#define PCRE_ERROR_DFA_UMLIMIT (-18)
#define PCRE_ERROR_DFA_WSSIZE (-19)
#define PCRE_ERROR_DFA_RECURSE (-20)
#define PCRE_ERROR_RECURSIONLIMIT (-21)
#define PCRE_ERROR_NULLWSLIMIT (-22) /* No longer actually used */
#define PCRE_ERROR_BADNEWLINE (-23)
#define PCRE_ERROR_BADOFFSET (-24)
#define PCRE_ERROR_SHORTUTF8 (-25)
#define PCRE_ERROR_SHORTUTF16 (-25) /* Same for 8/16 */
#define PCRE_ERROR_RECURSELOOP (-26)
#define PCRE_ERROR_JIT_STACKLIMIT (-27)
#define PCRE_ERROR_BADMODE (-28)
#define PCRE_ERROR_BADENDIANNESS (-29)
#define PCRE_ERROR_DFA_BADRESTART (-30)
#define PCRE_ERROR_JIT_BADOPTION (-31)
#define PCRE_ERROR_BADLENGTH (-32)
#define PCRE_ERROR_UNSET (-33)
/* Specific error codes for UTF-8 validity checks */
#define PCRE_UTF8_ERR0 0
#define PCRE_UTF8_ERR1 1
#define PCRE_UTF8_ERR2 2
#define PCRE_UTF8_ERR3 3
#define PCRE_UTF8_ERR4 4
#define PCRE_UTF8_ERR5 5
#define PCRE_UTF8_ERR6 6
#define PCRE_UTF8_ERR7 7
#define PCRE_UTF8_ERR8 8
#define PCRE_UTF8_ERR9 9
#define PCRE_UTF8_ERR10 10
#define PCRE_UTF8_ERR11 11
#define PCRE_UTF8_ERR12 12
#define PCRE_UTF8_ERR13 13
#define PCRE_UTF8_ERR14 14
#define PCRE_UTF8_ERR15 15
#define PCRE_UTF8_ERR16 16
#define PCRE_UTF8_ERR17 17
#define PCRE_UTF8_ERR18 18
#define PCRE_UTF8_ERR19 19
#define PCRE_UTF8_ERR20 20
#define PCRE_UTF8_ERR21 21
#define PCRE_UTF8_ERR22 22 /* Unused (was non-character) */
/* Specific error codes for UTF-16 validity checks */
#define PCRE_UTF16_ERR0 0
#define PCRE_UTF16_ERR1 1
#define PCRE_UTF16_ERR2 2
#define PCRE_UTF16_ERR3 3
#define PCRE_UTF16_ERR4 4 /* Unused (was non-character) */
/* Specific error codes for UTF-32 validity checks */
#define PCRE_UTF32_ERR0 0
#define PCRE_UTF32_ERR1 1
#define PCRE_UTF32_ERR2 2 /* Unused (was non-character) */
#define PCRE_UTF32_ERR3 3
/* Request types for pcre_fullinfo() */
#define PCRE_INFO_OPTIONS 0
#define PCRE_INFO_SIZE 1
#define PCRE_INFO_CAPTURECOUNT 2
#define PCRE_INFO_BACKREFMAX 3
#define PCRE_INFO_FIRSTBYTE 4
#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */
#define PCRE_INFO_FIRSTTABLE 5
#define PCRE_INFO_LASTLITERAL 6
#define PCRE_INFO_NAMEENTRYSIZE 7
#define PCRE_INFO_NAMECOUNT 8
#define PCRE_INFO_NAMETABLE 9
#define PCRE_INFO_STUDYSIZE 10
#define PCRE_INFO_DEFAULT_TABLES 11
#define PCRE_INFO_OKPARTIAL 12
#define PCRE_INFO_JCHANGED 13
#define PCRE_INFO_HASCRORLF 14
#define PCRE_INFO_MINLENGTH 15
#define PCRE_INFO_JIT 16
#define PCRE_INFO_JITSIZE 17
#define PCRE_INFO_MAXLOOKBEHIND 18
#define PCRE_INFO_FIRSTCHARACTER 19
#define PCRE_INFO_FIRSTCHARACTERFLAGS 20
#define PCRE_INFO_REQUIREDCHAR 21
#define PCRE_INFO_REQUIREDCHARFLAGS 22
#define PCRE_INFO_MATCHLIMIT 23
#define PCRE_INFO_RECURSIONLIMIT 24
#define PCRE_INFO_MATCH_EMPTY 25
/* Request types for pcre_config(). Do not re-arrange, in order to remain
compatible. */
#define PCRE_CONFIG_UTF8 0
#define PCRE_CONFIG_NEWLINE 1
#define PCRE_CONFIG_LINK_SIZE 2
#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3
#define PCRE_CONFIG_MATCH_LIMIT 4
#define PCRE_CONFIG_STACKRECURSE 5
#define PCRE_CONFIG_UNICODE_PROPERTIES 6
#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7
#define PCRE_CONFIG_BSR 8
#define PCRE_CONFIG_JIT 9
#define PCRE_CONFIG_UTF16 10
#define PCRE_CONFIG_JITTARGET 11
#define PCRE_CONFIG_UTF32 12
#define PCRE_CONFIG_PARENS_LIMIT 13
/* Request types for pcre_study(). Do not re-arrange, in order to remain
compatible. */
#define PCRE_STUDY_JIT_COMPILE 0x0001
#define PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE 0x0002
#define PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE 0x0004
#define PCRE_STUDY_EXTRA_NEEDED 0x0008
/* Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine
these bits, just add new ones on the end, in order to remain compatible. */
#define PCRE_EXTRA_STUDY_DATA 0x0001
#define PCRE_EXTRA_MATCH_LIMIT 0x0002
#define PCRE_EXTRA_CALLOUT_DATA 0x0004
#define PCRE_EXTRA_TABLES 0x0008
#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010
#define PCRE_EXTRA_MARK 0x0020
#define PCRE_EXTRA_EXECUTABLE_JIT 0x0040
/* Types */
struct real_pcre8_or_16; /* declaration; the definition is private */
typedef struct real_pcre8_or_16 pcre;
struct real_pcre8_or_16; /* declaration; the definition is private */
typedef struct real_pcre8_or_16 pcre16;
struct real_pcre32; /* declaration; the definition is private */
typedef struct real_pcre32 pcre32;
struct real_pcre_jit_stack; /* declaration; the definition is private */
typedef struct real_pcre_jit_stack pcre_jit_stack;
struct real_pcre16_jit_stack; /* declaration; the definition is private */
typedef struct real_pcre16_jit_stack pcre16_jit_stack;
struct real_pcre32_jit_stack; /* declaration; the definition is private */
typedef struct real_pcre32_jit_stack pcre32_jit_stack;
/* If PCRE is compiled with 16 bit character support, PCRE_UCHAR16 must contain
a 16 bit wide signed data type. Otherwise it can be a dummy data type since
pcre16 functions are not implemented. There is a check for this in pcre_internal.h. */
#ifndef PCRE_UCHAR16
#define PCRE_UCHAR16 unsigned short
#endif
#ifndef PCRE_SPTR16
#define PCRE_SPTR16 const PCRE_UCHAR16 *
#endif
/* If PCRE is compiled with 32 bit character support, PCRE_UCHAR32 must contain
a 32 bit wide signed data type. Otherwise it can be a dummy data type since
pcre32 functions are not implemented. There is a check for this in pcre_internal.h. */
#ifndef PCRE_UCHAR32
#define PCRE_UCHAR32 unsigned int
#endif
#ifndef PCRE_SPTR32
#define PCRE_SPTR32 const PCRE_UCHAR32 *
#endif
/* When PCRE is compiled as a C++ library, the subject pointer type can be
replaced with a custom type. For conventional use, the public interface is a
const char *. */
#ifndef PCRE_SPTR
#define PCRE_SPTR const char *
#endif
/* The structure for passing additional data to pcre_exec(). This is defined in
such as way as to be extensible. Always add new fields at the end, in order to
remain compatible. */
typedef struct pcre_extra {
unsigned long int flags; /* Bits for which fields are set */
void *study_data; /* Opaque data from pcre_study() */
unsigned long int match_limit; /* Maximum number of calls to match() */
void *callout_data; /* Data passed back in callouts */
const unsigned char *tables; /* Pointer to character tables */
unsigned long int match_limit_recursion; /* Max recursive calls to match() */
unsigned char **mark; /* For passing back a mark pointer */
void *executable_jit; /* Contains a pointer to a compiled jit code */
} pcre_extra;
/* Same structure as above, but with 16 bit char pointers. */
typedef struct pcre16_extra {
unsigned long int flags; /* Bits for which fields are set */
void *study_data; /* Opaque data from pcre_study() */
unsigned long int match_limit; /* Maximum number of calls to match() */
void *callout_data; /* Data passed back in callouts */
const unsigned char *tables; /* Pointer to character tables */
unsigned long int match_limit_recursion; /* Max recursive calls to match() */
PCRE_UCHAR16 **mark; /* For passing back a mark pointer */
void *executable_jit; /* Contains a pointer to a compiled jit code */
} pcre16_extra;
/* Same structure as above, but with 32 bit char pointers. */
typedef struct pcre32_extra {
unsigned long int flags; /* Bits for which fields are set */
void *study_data; /* Opaque data from pcre_study() */
unsigned long int match_limit; /* Maximum number of calls to match() */
void *callout_data; /* Data passed back in callouts */
const unsigned char *tables; /* Pointer to character tables */
unsigned long int match_limit_recursion; /* Max recursive calls to match() */
PCRE_UCHAR32 **mark; /* For passing back a mark pointer */
void *executable_jit; /* Contains a pointer to a compiled jit code */
} pcre32_extra;
/* The structure for passing out data via the pcre_callout_function. We use a
structure so that new fields can be added on the end in future versions,
without changing the API of the function, thereby allowing old clients to work
without modification. */
typedef struct pcre_callout_block {
int version; /* Identifies version of block */
/* ------------------------ Version 0 ------------------------------- */
int callout_number; /* Number compiled into pattern */
int *offset_vector; /* The offset vector */
PCRE_SPTR subject; /* The subject being matched */
int subject_length; /* The length of the subject */
int start_match; /* Offset to start of this match attempt */
int current_position; /* Where we currently are in the subject */
int capture_top; /* Max current capture */
int capture_last; /* Most recently closed capture */
void *callout_data; /* Data passed in with the call */
/* ------------------- Added for Version 1 -------------------------- */
int pattern_position; /* Offset to next item in the pattern */
int next_item_length; /* Length of next item in the pattern */
/* ------------------- Added for Version 2 -------------------------- */
const unsigned char *mark; /* Pointer to current mark or NULL */
/* ------------------------------------------------------------------ */
} pcre_callout_block;
/* Same structure as above, but with 16 bit char pointers. */
typedef struct pcre16_callout_block {
int version; /* Identifies version of block */
/* ------------------------ Version 0 ------------------------------- */
int callout_number; /* Number compiled into pattern */
int *offset_vector; /* The offset vector */
PCRE_SPTR16 subject; /* The subject being matched */
int subject_length; /* The length of the subject */
int start_match; /* Offset to start of this match attempt */
int current_position; /* Where we currently are in the subject */
int capture_top; /* Max current capture */
int capture_last; /* Most recently closed capture */
void *callout_data; /* Data passed in with the call */
/* ------------------- Added for Version 1 -------------------------- */
int pattern_position; /* Offset to next item in the pattern */
int next_item_length; /* Length of next item in the pattern */
/* ------------------- Added for Version 2 -------------------------- */
const PCRE_UCHAR16 *mark; /* Pointer to current mark or NULL */
/* ------------------------------------------------------------------ */
} pcre16_callout_block;
/* Same structure as above, but with 32 bit char pointers. */
typedef struct pcre32_callout_block {
int version; /* Identifies version of block */
/* ------------------------ Version 0 ------------------------------- */
int callout_number; /* Number compiled into pattern */
int *offset_vector; /* The offset vector */
PCRE_SPTR32 subject; /* The subject being matched */
int subject_length; /* The length of the subject */
int start_match; /* Offset to start of this match attempt */
int current_position; /* Where we currently are in the subject */
int capture_top; /* Max current capture */
int capture_last; /* Most recently closed capture */
void *callout_data; /* Data passed in with the call */
/* ------------------- Added for Version 1 -------------------------- */
int pattern_position; /* Offset to next item in the pattern */
int next_item_length; /* Length of next item in the pattern */
/* ------------------- Added for Version 2 -------------------------- */
const PCRE_UCHAR32 *mark; /* Pointer to current mark or NULL */
/* ------------------------------------------------------------------ */
} pcre32_callout_block;
/* Indirection for store get and free functions. These can be set to
alternative malloc/free functions if required. Special ones are used in the
non-recursive case for "frames". There is also an optional callout function
that is triggered by the (?) regex item. For Virtual Pascal, these definitions
have to take another form. */
#ifndef VPCOMPAT
PCRE_EXP_DECL void *(*pcre_malloc)(size_t);
PCRE_EXP_DECL void (*pcre_free)(void *);
PCRE_EXP_DECL void *(*pcre_stack_malloc)(size_t);
PCRE_EXP_DECL void (*pcre_stack_free)(void *);
PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *);
PCRE_EXP_DECL int (*pcre_stack_guard)(void);
PCRE_EXP_DECL void *(*pcre16_malloc)(size_t);
PCRE_EXP_DECL void (*pcre16_free)(void *);
PCRE_EXP_DECL void *(*pcre16_stack_malloc)(size_t);
PCRE_EXP_DECL void (*pcre16_stack_free)(void *);
PCRE_EXP_DECL int (*pcre16_callout)(pcre16_callout_block *);
PCRE_EXP_DECL int (*pcre16_stack_guard)(void);
PCRE_EXP_DECL void *(*pcre32_malloc)(size_t);
PCRE_EXP_DECL void (*pcre32_free)(void *);
PCRE_EXP_DECL void *(*pcre32_stack_malloc)(size_t);
PCRE_EXP_DECL void (*pcre32_stack_free)(void *);
PCRE_EXP_DECL int (*pcre32_callout)(pcre32_callout_block *);
PCRE_EXP_DECL int (*pcre32_stack_guard)(void);
#else /* VPCOMPAT */
PCRE_EXP_DECL void *pcre_malloc(size_t);
PCRE_EXP_DECL void pcre_free(void *);
PCRE_EXP_DECL void *pcre_stack_malloc(size_t);
PCRE_EXP_DECL void pcre_stack_free(void *);
PCRE_EXP_DECL int pcre_callout(pcre_callout_block *);
PCRE_EXP_DECL int pcre_stack_guard(void);
PCRE_EXP_DECL void *pcre16_malloc(size_t);
PCRE_EXP_DECL void pcre16_free(void *);
PCRE_EXP_DECL void *pcre16_stack_malloc(size_t);
PCRE_EXP_DECL void pcre16_stack_free(void *);
PCRE_EXP_DECL int pcre16_callout(pcre16_callout_block *);
PCRE_EXP_DECL int pcre16_stack_guard(void);
PCRE_EXP_DECL void *pcre32_malloc(size_t);
PCRE_EXP_DECL void pcre32_free(void *);
PCRE_EXP_DECL void *pcre32_stack_malloc(size_t);
PCRE_EXP_DECL void pcre32_stack_free(void *);
PCRE_EXP_DECL int pcre32_callout(pcre32_callout_block *);
PCRE_EXP_DECL int pcre32_stack_guard(void);
#endif /* VPCOMPAT */
/* User defined callback which provides a stack just before the match starts. */
typedef pcre_jit_stack *(*pcre_jit_callback)(void *);
typedef pcre16_jit_stack *(*pcre16_jit_callback)(void *);
typedef pcre32_jit_stack *(*pcre32_jit_callback)(void *);
/* Exported PCRE functions */
PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *,
const unsigned char *);
PCRE_EXP_DECL pcre16 *pcre16_compile(PCRE_SPTR16, int, const char **, int *,
const unsigned char *);
PCRE_EXP_DECL pcre32 *pcre32_compile(PCRE_SPTR32, int, const char **, int *,
const unsigned char *);
PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **,
int *, const unsigned char *);
PCRE_EXP_DECL pcre16 *pcre16_compile2(PCRE_SPTR16, int, int *, const char **,
int *, const unsigned char *);
PCRE_EXP_DECL pcre32 *pcre32_compile2(PCRE_SPTR32, int, int *, const char **,
int *, const unsigned char *);
PCRE_EXP_DECL int pcre_config(int, void *);
PCRE_EXP_DECL int pcre16_config(int, void *);
PCRE_EXP_DECL int pcre32_config(int, void *);
PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *,
int *, int, const char *, char *, int);
PCRE_EXP_DECL int pcre16_copy_named_substring(const pcre16 *, PCRE_SPTR16,
int *, int, PCRE_SPTR16, PCRE_UCHAR16 *, int);
PCRE_EXP_DECL int pcre32_copy_named_substring(const pcre32 *, PCRE_SPTR32,
int *, int, PCRE_SPTR32, PCRE_UCHAR32 *, int);
PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int,
char *, int);
PCRE_EXP_DECL int pcre16_copy_substring(PCRE_SPTR16, int *, int, int,
PCRE_UCHAR16 *, int);
PCRE_EXP_DECL int pcre32_copy_substring(PCRE_SPTR32, int *, int, int,
PCRE_UCHAR32 *, int);
PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *,
const char *, int, int, int, int *, int , int *, int);
PCRE_EXP_DECL int pcre16_dfa_exec(const pcre16 *, const pcre16_extra *,
PCRE_SPTR16, int, int, int, int *, int , int *, int);
PCRE_EXP_DECL int pcre32_dfa_exec(const pcre32 *, const pcre32_extra *,
PCRE_SPTR32, int, int, int, int *, int , int *, int);
PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR,
int, int, int, int *, int);
PCRE_EXP_DECL int pcre16_exec(const pcre16 *, const pcre16_extra *,
PCRE_SPTR16, int, int, int, int *, int);
PCRE_EXP_DECL int pcre32_exec(const pcre32 *, const pcre32_extra *,
PCRE_SPTR32, int, int, int, int *, int);
PCRE_EXP_DECL int pcre_jit_exec(const pcre *, const pcre_extra *,
PCRE_SPTR, int, int, int, int *, int,
pcre_jit_stack *);
PCRE_EXP_DECL int pcre16_jit_exec(const pcre16 *, const pcre16_extra *,
PCRE_SPTR16, int, int, int, int *, int,
pcre16_jit_stack *);
PCRE_EXP_DECL int pcre32_jit_exec(const pcre32 *, const pcre32_extra *,
PCRE_SPTR32, int, int, int, int *, int,
pcre32_jit_stack *);
PCRE_EXP_DECL void pcre_free_substring(const char *);
PCRE_EXP_DECL void pcre16_free_substring(PCRE_SPTR16);
PCRE_EXP_DECL void pcre32_free_substring(PCRE_SPTR32);
PCRE_EXP_DECL void pcre_free_substring_list(const char **);
PCRE_EXP_DECL void pcre16_free_substring_list(PCRE_SPTR16 *);
PCRE_EXP_DECL void pcre32_free_substring_list(PCRE_SPTR32 *);
PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int,
void *);
PCRE_EXP_DECL int pcre16_fullinfo(const pcre16 *, const pcre16_extra *, int,
void *);
PCRE_EXP_DECL int pcre32_fullinfo(const pcre32 *, const pcre32_extra *, int,
void *);
PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *,
int *, int, const char *, const char **);
PCRE_EXP_DECL int pcre16_get_named_substring(const pcre16 *, PCRE_SPTR16,
int *, int, PCRE_SPTR16, PCRE_SPTR16 *);
PCRE_EXP_DECL int pcre32_get_named_substring(const pcre32 *, PCRE_SPTR32,
int *, int, PCRE_SPTR32, PCRE_SPTR32 *);
PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *);
PCRE_EXP_DECL int pcre16_get_stringnumber(const pcre16 *, PCRE_SPTR16);
PCRE_EXP_DECL int pcre32_get_stringnumber(const pcre32 *, PCRE_SPTR32);
PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *,
char **, char **);
PCRE_EXP_DECL int pcre16_get_stringtable_entries(const pcre16 *, PCRE_SPTR16,
PCRE_UCHAR16 **, PCRE_UCHAR16 **);
PCRE_EXP_DECL int pcre32_get_stringtable_entries(const pcre32 *, PCRE_SPTR32,
PCRE_UCHAR32 **, PCRE_UCHAR32 **);
PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int,
const char **);
PCRE_EXP_DECL int pcre16_get_substring(PCRE_SPTR16, int *, int, int,
PCRE_SPTR16 *);
PCRE_EXP_DECL int pcre32_get_substring(PCRE_SPTR32, int *, int, int,
PCRE_SPTR32 *);
PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int,
const char ***);
PCRE_EXP_DECL int pcre16_get_substring_list(PCRE_SPTR16, int *, int,
PCRE_SPTR16 **);
PCRE_EXP_DECL int pcre32_get_substring_list(PCRE_SPTR32, int *, int,
PCRE_SPTR32 **);
PCRE_EXP_DECL const unsigned char *pcre_maketables(void);
PCRE_EXP_DECL const unsigned char *pcre16_maketables(void);
PCRE_EXP_DECL const unsigned char *pcre32_maketables(void);
PCRE_EXP_DECL int pcre_refcount(pcre *, int);
PCRE_EXP_DECL int pcre16_refcount(pcre16 *, int);
PCRE_EXP_DECL int pcre32_refcount(pcre32 *, int);
PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **);
PCRE_EXP_DECL pcre16_extra *pcre16_study(const pcre16 *, int, const char **);
PCRE_EXP_DECL pcre32_extra *pcre32_study(const pcre32 *, int, const char **);
PCRE_EXP_DECL void pcre_free_study(pcre_extra *);
PCRE_EXP_DECL void pcre16_free_study(pcre16_extra *);
PCRE_EXP_DECL void pcre32_free_study(pcre32_extra *);
PCRE_EXP_DECL const char *pcre_version(void);
PCRE_EXP_DECL const char *pcre16_version(void);
PCRE_EXP_DECL const char *pcre32_version(void);
/* Utility functions for byte order swaps. */
PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *, pcre_extra *,
const unsigned char *);
PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *, pcre16_extra *,
const unsigned char *);
PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *, pcre32_extra *,
const unsigned char *);
PCRE_EXP_DECL int pcre16_utf16_to_host_byte_order(PCRE_UCHAR16 *,
PCRE_SPTR16, int, int *, int);
PCRE_EXP_DECL int pcre32_utf32_to_host_byte_order(PCRE_UCHAR32 *,
PCRE_SPTR32, int, int *, int);
/* JIT compiler related functions. */
PCRE_EXP_DECL pcre_jit_stack *pcre_jit_stack_alloc(int, int);
PCRE_EXP_DECL pcre16_jit_stack *pcre16_jit_stack_alloc(int, int);
PCRE_EXP_DECL pcre32_jit_stack *pcre32_jit_stack_alloc(int, int);
PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *);
PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *);
PCRE_EXP_DECL void pcre32_jit_stack_free(pcre32_jit_stack *);
PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *,
pcre_jit_callback, void *);
PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *,
pcre16_jit_callback, void *);
PCRE_EXP_DECL void pcre32_assign_jit_stack(pcre32_extra *,
pcre32_jit_callback, void *);
PCRE_EXP_DECL void pcre_jit_free_unused_memory(void);
PCRE_EXP_DECL void pcre16_jit_free_unused_memory(void);
PCRE_EXP_DECL void pcre32_jit_free_unused_memory(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* End of pcre.h */

View File

@ -0,0 +1,172 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sanjay Ghemawat
//
// Regular-expression based scanner for parsing an input stream.
//
// Example 1: parse a sequence of "var = number" entries from input:
//
// Scanner scanner(input);
// string var;
// int number;
// scanner.SetSkipExpression("\\s+"); // Skip any white space we encounter
// while (scanner.Consume("(\\w+) = (\\d+)", &var, &number)) {
// ...;
// }
#ifndef _PCRE_SCANNER_H
#define _PCRE_SCANNER_H
#include <assert.h>
#include <string>
#include <vector>
#include <pcrecpp.h>
#include <pcre_stringpiece.h>
namespace pcrecpp {
class PCRECPP_EXP_DEFN Scanner {
public:
Scanner();
explicit Scanner(const std::string& input);
~Scanner();
// Return current line number. The returned line-number is
// one-based. I.e. it returns 1 + the number of consumed newlines.
//
// Note: this method may be slow. It may take time proportional to
// the size of the input.
int LineNumber() const;
// Return the byte-offset that the scanner is looking in the
// input data;
int Offset() const;
// Return true iff the start of the remaining input matches "re"
bool LookingAt(const RE& re) const;
// Return true iff all of the following are true
// a. the start of the remaining input matches "re",
// b. if any arguments are supplied, matched sub-patterns can be
// parsed and stored into the arguments.
// If it returns true, it skips over the matched input and any
// following input that matches the "skip" regular expression.
bool Consume(const RE& re,
const Arg& arg0 = RE::no_arg,
const Arg& arg1 = RE::no_arg,
const Arg& arg2 = RE::no_arg
// TODO: Allow more arguments?
);
// Set the "skip" regular expression. If after consuming some data,
// a prefix of the input matches this RE, it is automatically
// skipped. For example, a programming language scanner would use
// a skip RE that matches white space and comments.
//
// scanner.SetSkipExpression("\\s+|//.*|/[*](.|\n)*?[*]/");
//
// Skipping repeats as long as it succeeds. We used to let people do
// this by writing "(...)*" in the regular expression, but that added
// up to lots of recursive calls within the pcre library, so now we
// control repetition explicitly via the function call API.
//
// You can pass NULL for "re" if you do not want any data to be skipped.
void Skip(const char* re); // DEPRECATED; does *not* repeat
void SetSkipExpression(const char* re);
// Temporarily pause "skip"ing. This
// Skip("Foo"); code ; DisableSkip(); code; EnableSkip()
// is similar to
// Skip("Foo"); code ; Skip(NULL); code ; Skip("Foo");
// but avoids creating/deleting new RE objects.
void DisableSkip();
// Reenable previously paused skipping. Any prefix of the input
// that matches the skip pattern is immediately dropped.
void EnableSkip();
/***** Special wrappers around SetSkip() for some common idioms *****/
// Arranges to skip whitespace, C comments, C++ comments.
// The overall RE is a disjunction of the following REs:
// \\s whitespace
// //.*\n C++ comment
// /[*](.|\n)*?[*]/ C comment (x*? means minimal repetitions of x)
// We get repetition via the semantics of SetSkipExpression, not by using *
void SkipCXXComments() {
SetSkipExpression("\\s|//.*\n|/[*](?:\n|.)*?[*]/");
}
void set_save_comments(bool comments) {
save_comments_ = comments;
}
bool save_comments() {
return save_comments_;
}
// Append to vector ranges the comments found in the
// byte range [start,end] (inclusive) of the input data.
// Only comments that were extracted entirely within that
// range are returned: no range splitting of atomically-extracted
// comments is performed.
void GetComments(int start, int end, std::vector<StringPiece> *ranges);
// Append to vector ranges the comments added
// since the last time this was called. This
// functionality is provided for efficiency when
// interleaving scanning with parsing.
void GetNextComments(std::vector<StringPiece> *ranges);
private:
std::string data_; // All the input data
StringPiece input_; // Unprocessed input
RE* skip_; // If non-NULL, RE for skipping input
bool should_skip_; // If true, use skip_
bool skip_repeat_; // If true, repeat skip_ as long as it works
bool save_comments_; // If true, aggregate the skip expression
// the skipped comments
// TODO: later consider requiring that the StringPieces be added
// in order by their start position
std::vector<StringPiece> *comments_;
// the offset into comments_ that has been returned by GetNextComments
int comments_offset_;
// helper function to consume *skip_ and honour
// save_comments_
void ConsumeSkip();
};
} // namespace pcrecpp
#endif /* _PCRE_SCANNER_H */

View File

@ -0,0 +1,180 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sanjay Ghemawat
//
// A string like object that points into another piece of memory.
// Useful for providing an interface that allows clients to easily
// pass in either a "const char*" or a "string".
//
// Arghh! I wish C++ literals were automatically of type "string".
#ifndef _PCRE_STRINGPIECE_H
#define _PCRE_STRINGPIECE_H
#include <cstring>
#include <string>
#include <iosfwd> // for ostream forward-declaration
#if 0
#define HAVE_TYPE_TRAITS
#include <type_traits.h>
#elif 0
#define HAVE_TYPE_TRAITS
#include <bits/type_traits.h>
#endif
#include <pcre.h>
namespace pcrecpp {
using std::memcmp;
using std::strlen;
using std::string;
class PCRECPP_EXP_DEFN StringPiece {
private:
const char* ptr_;
int length_;
public:
// We provide non-explicit singleton constructors so users can pass
// in a "const char*" or a "string" wherever a "StringPiece" is
// expected.
StringPiece()
: ptr_(NULL), length_(0) { }
StringPiece(const char* str)
: ptr_(str), length_(static_cast<int>(strlen(ptr_))) { }
StringPiece(const unsigned char* str)
: ptr_(reinterpret_cast<const char*>(str)),
length_(static_cast<int>(strlen(ptr_))) { }
StringPiece(const string& str)
: ptr_(str.data()), length_(static_cast<int>(str.size())) { }
StringPiece(const char* offset, int len)
: ptr_(offset), length_(len) { }
// data() may return a pointer to a buffer with embedded NULs, and the
// returned buffer may or may not be null terminated. Therefore it is
// typically a mistake to pass data() to a routine that expects a NUL
// terminated string. Use "as_string().c_str()" if you really need to do
// this. Or better yet, change your routine so it does not rely on NUL
// termination.
const char* data() const { return ptr_; }
int size() const { return length_; }
bool empty() const { return length_ == 0; }
void clear() { ptr_ = NULL; length_ = 0; }
void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; }
void set(const char* str) {
ptr_ = str;
length_ = static_cast<int>(strlen(str));
}
void set(const void* buffer, int len) {
ptr_ = reinterpret_cast<const char*>(buffer);
length_ = len;
}
char operator[](int i) const { return ptr_[i]; }
void remove_prefix(int n) {
ptr_ += n;
length_ -= n;
}
void remove_suffix(int n) {
length_ -= n;
}
bool operator==(const StringPiece& x) const {
return ((length_ == x.length_) &&
(memcmp(ptr_, x.ptr_, length_) == 0));
}
bool operator!=(const StringPiece& x) const {
return !(*this == x);
}
#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \
bool operator cmp (const StringPiece& x) const { \
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \
return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \
}
STRINGPIECE_BINARY_PREDICATE(<, <);
STRINGPIECE_BINARY_PREDICATE(<=, <);
STRINGPIECE_BINARY_PREDICATE(>=, >);
STRINGPIECE_BINARY_PREDICATE(>, >);
#undef STRINGPIECE_BINARY_PREDICATE
int compare(const StringPiece& x) const {
int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_);
if (r == 0) {
if (length_ < x.length_) r = -1;
else if (length_ > x.length_) r = +1;
}
return r;
}
string as_string() const {
return string(data(), size());
}
void CopyToString(string* target) const {
target->assign(ptr_, length_);
}
// Does "this" start with "x"
bool starts_with(const StringPiece& x) const {
return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0));
}
};
} // namespace pcrecpp
// ------------------------------------------------------------------
// Functions used to create STL containers that use StringPiece
// Remember that a StringPiece's lifetime had better be less than
// that of the underlying string or char*. If it is not, then you
// cannot safely store a StringPiece into an STL container
// ------------------------------------------------------------------
#ifdef HAVE_TYPE_TRAITS
// This makes vector<StringPiece> really fast for some STL implementations
template<> struct __type_traits<pcrecpp::StringPiece> {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_operator;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
#endif
// allow StringPiece to be logged
PCRECPP_EXP_DECL std::ostream& operator<<(std::ostream& o,
const pcrecpp::StringPiece& piece);
#endif /* _PCRE_STRINGPIECE_H */

710
third-party/libpcre/include/pcrecpp.h vendored Normal file
View File

@ -0,0 +1,710 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sanjay Ghemawat
// Support for PCRE_XXX modifiers added by Giuseppe Maxia, July 2005
#ifndef _PCRECPP_H
#define _PCRECPP_H
// C++ interface to the pcre regular-expression library. RE supports
// Perl-style regular expressions (with extensions like \d, \w, \s,
// ...).
//
// -----------------------------------------------------------------------
// REGEXP SYNTAX:
//
// This module is part of the pcre library and hence supports its syntax
// for regular expressions.
//
// The syntax is pretty similar to Perl's. For those not familiar
// with Perl's regular expressions, here are some examples of the most
// commonly used extensions:
//
// "hello (\\w+) world" -- \w matches a "word" character
// "version (\\d+)" -- \d matches a digit
// "hello\\s+world" -- \s matches any whitespace character
// "\\b(\\w+)\\b" -- \b matches empty string at a word boundary
// "(?i)hello" -- (?i) turns on case-insensitive matching
// "/\\*(.*?)\\*/" -- .*? matches . minimum no. of times possible
//
// -----------------------------------------------------------------------
// MATCHING INTERFACE:
//
// The "FullMatch" operation checks that supplied text matches a
// supplied pattern exactly.
//
// Example: successful match
// pcrecpp::RE re("h.*o");
// re.FullMatch("hello");
//
// Example: unsuccessful match (requires full match):
// pcrecpp::RE re("e");
// !re.FullMatch("hello");
//
// Example: creating a temporary RE object:
// pcrecpp::RE("h.*o").FullMatch("hello");
//
// You can pass in a "const char*" or a "string" for "text". The
// examples below tend to use a const char*.
//
// You can, as in the different examples above, store the RE object
// explicitly in a variable or use a temporary RE object. The
// examples below use one mode or the other arbitrarily. Either
// could correctly be used for any of these examples.
//
// -----------------------------------------------------------------------
// MATCHING WITH SUB-STRING EXTRACTION:
//
// You can supply extra pointer arguments to extract matched subpieces.
//
// Example: extracts "ruby" into "s" and 1234 into "i"
// int i;
// string s;
// pcrecpp::RE re("(\\w+):(\\d+)");
// re.FullMatch("ruby:1234", &s, &i);
//
// Example: does not try to extract any extra sub-patterns
// re.FullMatch("ruby:1234", &s);
//
// Example: does not try to extract into NULL
// re.FullMatch("ruby:1234", NULL, &i);
//
// Example: integer overflow causes failure
// !re.FullMatch("ruby:1234567891234", NULL, &i);
//
// Example: fails because there aren't enough sub-patterns:
// !pcrecpp::RE("\\w+:\\d+").FullMatch("ruby:1234", &s);
//
// Example: fails because string cannot be stored in integer
// !pcrecpp::RE("(.*)").FullMatch("ruby", &i);
//
// The provided pointer arguments can be pointers to any scalar numeric
// type, or one of
// string (matched piece is copied to string)
// StringPiece (StringPiece is mutated to point to matched piece)
// T (where "bool T::ParseFrom(const char*, int)" exists)
// NULL (the corresponding matched sub-pattern is not copied)
//
// CAVEAT: An optional sub-pattern that does not exist in the matched
// string is assigned the empty string. Therefore, the following will
// return false (because the empty string is not a valid number):
// int number;
// pcrecpp::RE::FullMatch("abc", "[a-z]+(\\d+)?", &number);
//
// -----------------------------------------------------------------------
// DO_MATCH
//
// The matching interface supports at most 16 arguments per call.
// If you need more, consider using the more general interface
// pcrecpp::RE::DoMatch(). See pcrecpp.h for the signature for DoMatch.
//
// -----------------------------------------------------------------------
// PARTIAL MATCHES
//
// You can use the "PartialMatch" operation when you want the pattern
// to match any substring of the text.
//
// Example: simple search for a string:
// pcrecpp::RE("ell").PartialMatch("hello");
//
// Example: find first number in a string:
// int number;
// pcrecpp::RE re("(\\d+)");
// re.PartialMatch("x*100 + 20", &number);
// assert(number == 100);
//
// -----------------------------------------------------------------------
// UTF-8 AND THE MATCHING INTERFACE:
//
// By default, pattern and text are plain text, one byte per character.
// The UTF8 flag, passed to the constructor, causes both pattern
// and string to be treated as UTF-8 text, still a byte stream but
// potentially multiple bytes per character. In practice, the text
// is likelier to be UTF-8 than the pattern, but the match returned
// may depend on the UTF8 flag, so always use it when matching
// UTF8 text. E.g., "." will match one byte normally but with UTF8
// set may match up to three bytes of a multi-byte character.
//
// Example:
// pcrecpp::RE_Options options;
// options.set_utf8();
// pcrecpp::RE re(utf8_pattern, options);
// re.FullMatch(utf8_string);
//
// Example: using the convenience function UTF8():
// pcrecpp::RE re(utf8_pattern, pcrecpp::UTF8());
// re.FullMatch(utf8_string);
//
// NOTE: The UTF8 option is ignored if pcre was not configured with the
// --enable-utf8 flag.
//
// -----------------------------------------------------------------------
// PASSING MODIFIERS TO THE REGULAR EXPRESSION ENGINE
//
// PCRE defines some modifiers to change the behavior of the regular
// expression engine.
// The C++ wrapper defines an auxiliary class, RE_Options, as a vehicle
// to pass such modifiers to a RE class.
//
// Currently, the following modifiers are supported
//
// modifier description Perl corresponding
//
// PCRE_CASELESS case insensitive match /i
// PCRE_MULTILINE multiple lines match /m
// PCRE_DOTALL dot matches newlines /s
// PCRE_DOLLAR_ENDONLY $ matches only at end N/A
// PCRE_EXTRA strict escape parsing N/A
// PCRE_EXTENDED ignore whitespaces /x
// PCRE_UTF8 handles UTF8 chars built-in
// PCRE_UNGREEDY reverses * and *? N/A
// PCRE_NO_AUTO_CAPTURE disables matching parens N/A (*)
//
// (For a full account on how each modifier works, please check the
// PCRE API reference manual).
//
// (*) Both Perl and PCRE allow non matching parentheses by means of the
// "?:" modifier within the pattern itself. e.g. (?:ab|cd) does not
// capture, while (ab|cd) does.
//
// For each modifier, there are two member functions whose name is made
// out of the modifier in lowercase, without the "PCRE_" prefix. For
// instance, PCRE_CASELESS is handled by
// bool caseless(),
// which returns true if the modifier is set, and
// RE_Options & set_caseless(bool),
// which sets or unsets the modifier.
//
// Moreover, PCRE_EXTRA_MATCH_LIMIT can be accessed through the
// set_match_limit() and match_limit() member functions.
// Setting match_limit to a non-zero value will limit the executation of
// pcre to keep it from doing bad things like blowing the stack or taking
// an eternity to return a result. A value of 5000 is good enough to stop
// stack blowup in a 2MB thread stack. Setting match_limit to zero will
// disable match limiting. Alternately, you can set match_limit_recursion()
// which uses PCRE_EXTRA_MATCH_LIMIT_RECURSION to limit how much pcre
// recurses. match_limit() caps the number of matches pcre does;
// match_limit_recrusion() caps the depth of recursion.
//
// Normally, to pass one or more modifiers to a RE class, you declare
// a RE_Options object, set the appropriate options, and pass this
// object to a RE constructor. Example:
//
// RE_options opt;
// opt.set_caseless(true);
//
// if (RE("HELLO", opt).PartialMatch("hello world")) ...
//
// RE_options has two constructors. The default constructor takes no
// arguments and creates a set of flags that are off by default.
//
// The optional parameter 'option_flags' is to facilitate transfer
// of legacy code from C programs. This lets you do
// RE(pattern, RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).PartialMatch(str);
//
// But new code is better off doing
// RE(pattern,
// RE_Options().set_caseless(true).set_multiline(true)).PartialMatch(str);
// (See below)
//
// If you are going to pass one of the most used modifiers, there are some
// convenience functions that return a RE_Options class with the
// appropriate modifier already set:
// CASELESS(), UTF8(), MULTILINE(), DOTALL(), EXTENDED()
//
// If you need to set several options at once, and you don't want to go
// through the pains of declaring a RE_Options object and setting several
// options, there is a parallel method that give you such ability on the
// fly. You can concatenate several set_xxxxx member functions, since each
// of them returns a reference to its class object. e.g.: to pass
// PCRE_CASELESS, PCRE_EXTENDED, and PCRE_MULTILINE to a RE with one
// statement, you may write
//
// RE(" ^ xyz \\s+ .* blah$", RE_Options()
// .set_caseless(true)
// .set_extended(true)
// .set_multiline(true)).PartialMatch(sometext);
//
// -----------------------------------------------------------------------
// SCANNING TEXT INCREMENTALLY
//
// The "Consume" operation may be useful if you want to repeatedly
// match regular expressions at the front of a string and skip over
// them as they match. This requires use of the "StringPiece" type,
// which represents a sub-range of a real string. Like RE, StringPiece
// is defined in the pcrecpp namespace.
//
// Example: read lines of the form "var = value" from a string.
// string contents = ...; // Fill string somehow
// pcrecpp::StringPiece input(contents); // Wrap in a StringPiece
//
// string var;
// int value;
// pcrecpp::RE re("(\\w+) = (\\d+)\n");
// while (re.Consume(&input, &var, &value)) {
// ...;
// }
//
// Each successful call to "Consume" will set "var/value", and also
// advance "input" so it points past the matched text.
//
// The "FindAndConsume" operation is similar to "Consume" but does not
// anchor your match at the beginning of the string. For example, you
// could extract all words from a string by repeatedly calling
// pcrecpp::RE("(\\w+)").FindAndConsume(&input, &word)
//
// -----------------------------------------------------------------------
// PARSING HEX/OCTAL/C-RADIX NUMBERS
//
// By default, if you pass a pointer to a numeric value, the
// corresponding text is interpreted as a base-10 number. You can
// instead wrap the pointer with a call to one of the operators Hex(),
// Octal(), or CRadix() to interpret the text in another base. The
// CRadix operator interprets C-style "0" (base-8) and "0x" (base-16)
// prefixes, but defaults to base-10.
//
// Example:
// int a, b, c, d;
// pcrecpp::RE re("(.*) (.*) (.*) (.*)");
// re.FullMatch("100 40 0100 0x40",
// pcrecpp::Octal(&a), pcrecpp::Hex(&b),
// pcrecpp::CRadix(&c), pcrecpp::CRadix(&d));
// will leave 64 in a, b, c, and d.
//
// -----------------------------------------------------------------------
// REPLACING PARTS OF STRINGS
//
// You can replace the first match of "pattern" in "str" with
// "rewrite". Within "rewrite", backslash-escaped digits (\1 to \9)
// can be used to insert text matching corresponding parenthesized
// group from the pattern. \0 in "rewrite" refers to the entire
// matching text. E.g.,
//
// string s = "yabba dabba doo";
// pcrecpp::RE("b+").Replace("d", &s);
//
// will leave "s" containing "yada dabba doo". The result is true if
// the pattern matches and a replacement occurs, or false otherwise.
//
// GlobalReplace() is like Replace(), except that it replaces all
// occurrences of the pattern in the string with the rewrite.
// Replacements are not subject to re-matching. E.g.,
//
// string s = "yabba dabba doo";
// pcrecpp::RE("b+").GlobalReplace("d", &s);
//
// will leave "s" containing "yada dada doo". It returns the number
// of replacements made.
//
// Extract() is like Replace(), except that if the pattern matches,
// "rewrite" is copied into "out" (an additional argument) with
// substitutions. The non-matching portions of "text" are ignored.
// Returns true iff a match occurred and the extraction happened
// successfully. If no match occurs, the string is left unaffected.
#include <string>
#include <pcre.h>
#include <pcrecpparg.h> // defines the Arg class
// This isn't technically needed here, but we include it
// anyway so folks who include pcrecpp.h don't have to.
#include <pcre_stringpiece.h>
namespace pcrecpp {
#define PCRE_SET_OR_CLEAR(b, o) \
if (b) all_options_ |= (o); else all_options_ &= ~(o); \
return *this
#define PCRE_IS_SET(o) \
(all_options_ & o) == o
/***** Compiling regular expressions: the RE class *****/
// RE_Options allow you to set options to be passed along to pcre,
// along with other options we put on top of pcre.
// Only 9 modifiers, plus match_limit and match_limit_recursion,
// are supported now.
class PCRECPP_EXP_DEFN RE_Options {
public:
// constructor
RE_Options() : match_limit_(0), match_limit_recursion_(0), all_options_(0) {}
// alternative constructor.
// To facilitate transfer of legacy code from C programs
//
// This lets you do
// RE(pattern, RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).PartialMatch(str);
// But new code is better off doing
// RE(pattern,
// RE_Options().set_caseless(true).set_multiline(true)).PartialMatch(str);
RE_Options(int option_flags) : match_limit_(0), match_limit_recursion_(0),
all_options_(option_flags) {}
// we're fine with the default destructor, copy constructor, etc.
// accessors and mutators
int match_limit() const { return match_limit_; };
RE_Options &set_match_limit(int limit) {
match_limit_ = limit;
return *this;
}
int match_limit_recursion() const { return match_limit_recursion_; };
RE_Options &set_match_limit_recursion(int limit) {
match_limit_recursion_ = limit;
return *this;
}
bool caseless() const {
return PCRE_IS_SET(PCRE_CASELESS);
}
RE_Options &set_caseless(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_CASELESS);
}
bool multiline() const {
return PCRE_IS_SET(PCRE_MULTILINE);
}
RE_Options &set_multiline(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_MULTILINE);
}
bool dotall() const {
return PCRE_IS_SET(PCRE_DOTALL);
}
RE_Options &set_dotall(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_DOTALL);
}
bool extended() const {
return PCRE_IS_SET(PCRE_EXTENDED);
}
RE_Options &set_extended(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_EXTENDED);
}
bool dollar_endonly() const {
return PCRE_IS_SET(PCRE_DOLLAR_ENDONLY);
}
RE_Options &set_dollar_endonly(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_DOLLAR_ENDONLY);
}
bool extra() const {
return PCRE_IS_SET(PCRE_EXTRA);
}
RE_Options &set_extra(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_EXTRA);
}
bool ungreedy() const {
return PCRE_IS_SET(PCRE_UNGREEDY);
}
RE_Options &set_ungreedy(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_UNGREEDY);
}
bool utf8() const {
return PCRE_IS_SET(PCRE_UTF8);
}
RE_Options &set_utf8(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_UTF8);
}
bool no_auto_capture() const {
return PCRE_IS_SET(PCRE_NO_AUTO_CAPTURE);
}
RE_Options &set_no_auto_capture(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_NO_AUTO_CAPTURE);
}
RE_Options &set_all_options(int opt) {
all_options_ = opt;
return *this;
}
int all_options() const {
return all_options_ ;
}
// TODO: add other pcre flags
private:
int match_limit_;
int match_limit_recursion_;
int all_options_;
};
// These functions return some common RE_Options
static inline RE_Options UTF8() {
return RE_Options().set_utf8(true);
}
static inline RE_Options CASELESS() {
return RE_Options().set_caseless(true);
}
static inline RE_Options MULTILINE() {
return RE_Options().set_multiline(true);
}
static inline RE_Options DOTALL() {
return RE_Options().set_dotall(true);
}
static inline RE_Options EXTENDED() {
return RE_Options().set_extended(true);
}
// Interface for regular expression matching. Also corresponds to a
// pre-compiled regular expression. An "RE" object is safe for
// concurrent use by multiple threads.
class PCRECPP_EXP_DEFN RE {
public:
// We provide implicit conversions from strings so that users can
// pass in a string or a "const char*" wherever an "RE" is expected.
RE(const string& pat) { Init(pat, NULL); }
RE(const string& pat, const RE_Options& option) { Init(pat, &option); }
RE(const char* pat) { Init(pat, NULL); }
RE(const char* pat, const RE_Options& option) { Init(pat, &option); }
RE(const unsigned char* pat) {
Init(reinterpret_cast<const char*>(pat), NULL);
}
RE(const unsigned char* pat, const RE_Options& option) {
Init(reinterpret_cast<const char*>(pat), &option);
}
// Copy constructor & assignment - note that these are expensive
// because they recompile the expression.
RE(const RE& re) { Init(re.pattern_, &re.options_); }
const RE& operator=(const RE& re) {
if (this != &re) {
Cleanup();
// This is the code that originally came from Google
// Init(re.pattern_.c_str(), &re.options_);
// This is the replacement from Ari Pollak
Init(re.pattern_, &re.options_);
}
return *this;
}
~RE();
// The string specification for this RE. E.g.
// RE re("ab*c?d+");
// re.pattern(); // "ab*c?d+"
const string& pattern() const { return pattern_; }
// If RE could not be created properly, returns an error string.
// Else returns the empty string.
const string& error() const { return *error_; }
/***** The useful part: the matching interface *****/
// This is provided so one can do pattern.ReplaceAll() just as
// easily as ReplaceAll(pattern-text, ....)
bool FullMatch(const StringPiece& text,
const Arg& ptr1 = no_arg,
const Arg& ptr2 = no_arg,
const Arg& ptr3 = no_arg,
const Arg& ptr4 = no_arg,
const Arg& ptr5 = no_arg,
const Arg& ptr6 = no_arg,
const Arg& ptr7 = no_arg,
const Arg& ptr8 = no_arg,
const Arg& ptr9 = no_arg,
const Arg& ptr10 = no_arg,
const Arg& ptr11 = no_arg,
const Arg& ptr12 = no_arg,
const Arg& ptr13 = no_arg,
const Arg& ptr14 = no_arg,
const Arg& ptr15 = no_arg,
const Arg& ptr16 = no_arg) const;
bool PartialMatch(const StringPiece& text,
const Arg& ptr1 = no_arg,
const Arg& ptr2 = no_arg,
const Arg& ptr3 = no_arg,
const Arg& ptr4 = no_arg,
const Arg& ptr5 = no_arg,
const Arg& ptr6 = no_arg,
const Arg& ptr7 = no_arg,
const Arg& ptr8 = no_arg,
const Arg& ptr9 = no_arg,
const Arg& ptr10 = no_arg,
const Arg& ptr11 = no_arg,
const Arg& ptr12 = no_arg,
const Arg& ptr13 = no_arg,
const Arg& ptr14 = no_arg,
const Arg& ptr15 = no_arg,
const Arg& ptr16 = no_arg) const;
bool Consume(StringPiece* input,
const Arg& ptr1 = no_arg,
const Arg& ptr2 = no_arg,
const Arg& ptr3 = no_arg,
const Arg& ptr4 = no_arg,
const Arg& ptr5 = no_arg,
const Arg& ptr6 = no_arg,
const Arg& ptr7 = no_arg,
const Arg& ptr8 = no_arg,
const Arg& ptr9 = no_arg,
const Arg& ptr10 = no_arg,
const Arg& ptr11 = no_arg,
const Arg& ptr12 = no_arg,
const Arg& ptr13 = no_arg,
const Arg& ptr14 = no_arg,
const Arg& ptr15 = no_arg,
const Arg& ptr16 = no_arg) const;
bool FindAndConsume(StringPiece* input,
const Arg& ptr1 = no_arg,
const Arg& ptr2 = no_arg,
const Arg& ptr3 = no_arg,
const Arg& ptr4 = no_arg,
const Arg& ptr5 = no_arg,
const Arg& ptr6 = no_arg,
const Arg& ptr7 = no_arg,
const Arg& ptr8 = no_arg,
const Arg& ptr9 = no_arg,
const Arg& ptr10 = no_arg,
const Arg& ptr11 = no_arg,
const Arg& ptr12 = no_arg,
const Arg& ptr13 = no_arg,
const Arg& ptr14 = no_arg,
const Arg& ptr15 = no_arg,
const Arg& ptr16 = no_arg) const;
bool Replace(const StringPiece& rewrite,
string *str) const;
int GlobalReplace(const StringPiece& rewrite,
string *str) const;
bool Extract(const StringPiece &rewrite,
const StringPiece &text,
string *out) const;
// Escapes all potentially meaningful regexp characters in
// 'unquoted'. The returned string, used as a regular expression,
// will exactly match the original string. For example,
// 1.5-2.0?
// may become:
// 1\.5\-2\.0\?
// Note QuoteMeta behaves the same as perl's QuoteMeta function,
// *except* that it escapes the NUL character (\0) as backslash + 0,
// rather than backslash + NUL.
static string QuoteMeta(const StringPiece& unquoted);
/***** Generic matching interface *****/
// Type of match (TODO: Should be restructured as part of RE_Options)
enum Anchor {
UNANCHORED, // No anchoring
ANCHOR_START, // Anchor at start only
ANCHOR_BOTH // Anchor at start and end
};
// General matching routine. Stores the length of the match in
// "*consumed" if successful.
bool DoMatch(const StringPiece& text,
Anchor anchor,
int* consumed,
const Arg* const* args, int n) const;
// Return the number of capturing subpatterns, or -1 if the
// regexp wasn't valid on construction.
int NumberOfCapturingGroups() const;
// The default value for an argument, to indicate the end of the argument
// list. This must be used only in optional argument defaults. It should NOT
// be passed explicitly. Some people have tried to use it like this:
//
// FullMatch(x, y, &z, no_arg, &w);
//
// This is a mistake, and will not work.
static Arg no_arg;
private:
void Init(const string& pattern, const RE_Options* options);
void Cleanup();
// Match against "text", filling in "vec" (up to "vecsize" * 2/3) with
// pairs of integers for the beginning and end positions of matched
// text. The first pair corresponds to the entire matched text;
// subsequent pairs correspond, in order, to parentheses-captured
// matches. Returns the number of pairs (one more than the number of
// the last subpattern with a match) if matching was successful
// and zero if the match failed.
// I.e. for RE("(foo)|(bar)|(baz)") it will return 2, 3, and 4 when matching
// against "foo", "bar", and "baz" respectively.
// When matching RE("(foo)|hello") against "hello", it will return 1.
// But the values for all subpattern are filled in into "vec".
int TryMatch(const StringPiece& text,
int startpos,
Anchor anchor,
bool empty_ok,
int *vec,
int vecsize) const;
// Append the "rewrite" string, with backslash subsitutions from "text"
// and "vec", to string "out".
bool Rewrite(string *out,
const StringPiece& rewrite,
const StringPiece& text,
int *vec,
int veclen) const;
// internal implementation for DoMatch
bool DoMatchImpl(const StringPiece& text,
Anchor anchor,
int* consumed,
const Arg* const args[],
int n,
int* vec,
int vecsize) const;
// Compile the regexp for the specified anchoring mode
pcre* Compile(Anchor anchor);
string pattern_;
RE_Options options_;
pcre* re_full_; // For full matches
pcre* re_partial_; // For partial matches
const string* error_; // Error indicator (or points to empty string)
};
} // namespace pcrecpp
#endif /* _PCRECPP_H */

174
third-party/libpcre/include/pcrecpparg.h vendored Normal file
View File

@ -0,0 +1,174 @@
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sanjay Ghemawat
#ifndef _PCRECPPARG_H
#define _PCRECPPARG_H
#include <stdlib.h> // for NULL
#include <string>
#include <pcre.h>
namespace pcrecpp {
class StringPiece;
// Hex/Octal/Binary?
// Special class for parsing into objects that define a ParseFrom() method
template <class T>
class _RE_MatchObject {
public:
static inline bool Parse(const char* str, int n, void* dest) {
if (dest == NULL) return true;
T* object = reinterpret_cast<T*>(dest);
return object->ParseFrom(str, n);
}
};
class PCRECPP_EXP_DEFN Arg {
public:
// Empty constructor so we can declare arrays of Arg
Arg();
// Constructor specially designed for NULL arguments
Arg(void*);
typedef bool (*Parser)(const char* str, int n, void* dest);
// Type-specific parsers
#define PCRE_MAKE_PARSER(type,name) \
Arg(type* p) : arg_(p), parser_(name) { } \
Arg(type* p, Parser parser) : arg_(p), parser_(parser) { }
PCRE_MAKE_PARSER(char, parse_char);
PCRE_MAKE_PARSER(unsigned char, parse_uchar);
PCRE_MAKE_PARSER(short, parse_short);
PCRE_MAKE_PARSER(unsigned short, parse_ushort);
PCRE_MAKE_PARSER(int, parse_int);
PCRE_MAKE_PARSER(unsigned int, parse_uint);
PCRE_MAKE_PARSER(long, parse_long);
PCRE_MAKE_PARSER(unsigned long, parse_ulong);
#if 1
PCRE_MAKE_PARSER(long long, parse_longlong);
#endif
#if 1
PCRE_MAKE_PARSER(unsigned long long, parse_ulonglong);
#endif
PCRE_MAKE_PARSER(float, parse_float);
PCRE_MAKE_PARSER(double, parse_double);
PCRE_MAKE_PARSER(std::string, parse_string);
PCRE_MAKE_PARSER(StringPiece, parse_stringpiece);
#undef PCRE_MAKE_PARSER
// Generic constructor
template <class T> Arg(T*, Parser parser);
// Generic constructor template
template <class T> Arg(T* p)
: arg_(p), parser_(_RE_MatchObject<T>::Parse) {
}
// Parse the data
bool Parse(const char* str, int n) const;
private:
void* arg_;
Parser parser_;
static bool parse_null (const char* str, int n, void* dest);
static bool parse_char (const char* str, int n, void* dest);
static bool parse_uchar (const char* str, int n, void* dest);
static bool parse_float (const char* str, int n, void* dest);
static bool parse_double (const char* str, int n, void* dest);
static bool parse_string (const char* str, int n, void* dest);
static bool parse_stringpiece (const char* str, int n, void* dest);
#define PCRE_DECLARE_INTEGER_PARSER(name) \
private: \
static bool parse_ ## name(const char* str, int n, void* dest); \
static bool parse_ ## name ## _radix( \
const char* str, int n, void* dest, int radix); \
public: \
static bool parse_ ## name ## _hex(const char* str, int n, void* dest); \
static bool parse_ ## name ## _octal(const char* str, int n, void* dest); \
static bool parse_ ## name ## _cradix(const char* str, int n, void* dest)
PCRE_DECLARE_INTEGER_PARSER(short);
PCRE_DECLARE_INTEGER_PARSER(ushort);
PCRE_DECLARE_INTEGER_PARSER(int);
PCRE_DECLARE_INTEGER_PARSER(uint);
PCRE_DECLARE_INTEGER_PARSER(long);
PCRE_DECLARE_INTEGER_PARSER(ulong);
PCRE_DECLARE_INTEGER_PARSER(longlong);
PCRE_DECLARE_INTEGER_PARSER(ulonglong);
#undef PCRE_DECLARE_INTEGER_PARSER
};
inline Arg::Arg() : arg_(NULL), parser_(parse_null) { }
inline Arg::Arg(void* p) : arg_(p), parser_(parse_null) { }
inline bool Arg::Parse(const char* str, int n) const {
return (*parser_)(str, n, arg_);
}
// This part of the parser, appropriate only for ints, deals with bases
#define MAKE_INTEGER_PARSER(type, name) \
inline Arg Hex(type* ptr) { \
return Arg(ptr, Arg::parse_ ## name ## _hex); } \
inline Arg Octal(type* ptr) { \
return Arg(ptr, Arg::parse_ ## name ## _octal); } \
inline Arg CRadix(type* ptr) { \
return Arg(ptr, Arg::parse_ ## name ## _cradix); }
MAKE_INTEGER_PARSER(short, short) /* */
MAKE_INTEGER_PARSER(unsigned short, ushort) /* */
MAKE_INTEGER_PARSER(int, int) /* Don't use semicolons */
MAKE_INTEGER_PARSER(unsigned int, uint) /* after these statement */
MAKE_INTEGER_PARSER(long, long) /* because they can cause */
MAKE_INTEGER_PARSER(unsigned long, ulong) /* compiler warnings if */
#if 1 /* the checking level is */
MAKE_INTEGER_PARSER(long long, longlong) /* turned up high enough. */
#endif /* */
#if 1 /* */
MAKE_INTEGER_PARSER(unsigned long long, ulonglong) /* */
#endif
#undef PCRE_IS_SET
#undef PCRE_SET_OR_CLEAR
#undef MAKE_INTEGER_PARSER
} // namespace pcrecpp
#endif /* _PCRECPPARG_H */

146
third-party/libpcre/include/pcreposix.h vendored Normal file
View File

@ -0,0 +1,146 @@
/*************************************************
* Perl-Compatible Regular Expressions *
*************************************************/
#ifndef _PCREPOSIX_H
#define _PCREPOSIX_H
/* This is the header for the POSIX wrapper interface to the PCRE Perl-
Compatible Regular Expression library. It defines the things POSIX says should
be there. I hope.
Copyright (c) 1997-2012 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
/* Have to include stdlib.h in order to ensure that size_t is defined. */
#include <stdlib.h>
/* Allow for C++ users */
#ifdef __cplusplus
extern "C" {
#endif
/* Options, mostly defined by POSIX, but with some extras. */
#define REG_ICASE 0x0001 /* Maps to PCRE_CASELESS */
#define REG_NEWLINE 0x0002 /* Maps to PCRE_MULTILINE */
#define REG_NOTBOL 0x0004 /* Maps to PCRE_NOTBOL */
#define REG_NOTEOL 0x0008 /* Maps to PCRE_NOTEOL */
#define REG_DOTALL 0x0010 /* NOT defined by POSIX; maps to PCRE_DOTALL */
#define REG_NOSUB 0x0020 /* Maps to PCRE_NO_AUTO_CAPTURE */
#define REG_UTF8 0x0040 /* NOT defined by POSIX; maps to PCRE_UTF8 */
#define REG_STARTEND 0x0080 /* BSD feature: pass subject string by so,eo */
#define REG_NOTEMPTY 0x0100 /* NOT defined by POSIX; maps to PCRE_NOTEMPTY */
#define REG_UNGREEDY 0x0200 /* NOT defined by POSIX; maps to PCRE_UNGREEDY */
#define REG_UCP 0x0400 /* NOT defined by POSIX; maps to PCRE_UCP */
/* This is not used by PCRE, but by defining it we make it easier
to slot PCRE into existing programs that make POSIX calls. */
#define REG_EXTENDED 0
/* Error values. Not all these are relevant or used by the wrapper. */
enum {
REG_ASSERT = 1, /* internal error ? */
REG_BADBR, /* invalid repeat counts in {} */
REG_BADPAT, /* pattern error */
REG_BADRPT, /* ? * + invalid */
REG_EBRACE, /* unbalanced {} */
REG_EBRACK, /* unbalanced [] */
REG_ECOLLATE, /* collation error - not relevant */
REG_ECTYPE, /* bad class */
REG_EESCAPE, /* bad escape sequence */
REG_EMPTY, /* empty expression */
REG_EPAREN, /* unbalanced () */
REG_ERANGE, /* bad range inside [] */
REG_ESIZE, /* expression too big */
REG_ESPACE, /* failed to get memory */
REG_ESUBREG, /* bad back reference */
REG_INVARG, /* bad argument */
REG_NOMATCH /* match failed */
};
/* The structure representing a compiled regular expression. */
typedef struct {
void *re_pcre;
size_t re_nsub;
size_t re_erroffset;
} regex_t;
/* The structure in which a captured offset is returned. */
typedef int regoff_t;
typedef struct {
regoff_t rm_so;
regoff_t rm_eo;
} regmatch_t;
/* When an application links to a PCRE DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE, the appropriate
export settings are needed, and are set in pcreposix.c before including this
file. */
#if defined(_WIN32) && !defined(PCRE_STATIC) && !defined(PCREPOSIX_EXP_DECL)
# define PCREPOSIX_EXP_DECL extern __declspec(dllimport)
# define PCREPOSIX_EXP_DEFN __declspec(dllimport)
#endif
/* By default, we use the standard "extern" declarations. */
#ifndef PCREPOSIX_EXP_DECL
# ifdef __cplusplus
# define PCREPOSIX_EXP_DECL extern "C"
# define PCREPOSIX_EXP_DEFN extern "C"
# else
# define PCREPOSIX_EXP_DECL extern
# define PCREPOSIX_EXP_DEFN extern
# endif
#endif
/* The functions */
PCREPOSIX_EXP_DECL int regcomp(regex_t *, const char *, int);
PCREPOSIX_EXP_DECL int regexec(const regex_t *, const char *, size_t,
regmatch_t *, int);
PCREPOSIX_EXP_DECL size_t regerror(int, const regex_t *, char *, size_t);
PCREPOSIX_EXP_DECL void regfree(regex_t *);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* End of pcreposix.h */

Some files were not shown because too many files have changed in this diff Show More