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:
commit
3662ce18a6
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
@ -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>
|
||||
|
@ -115,3 +115,4 @@ enum NvimAutoCommandEvent: Int {
|
||||
case winleave = 109
|
||||
case winnew = 110
|
||||
}
|
||||
|
||||
|
27
NvimView/NvimView/NvimCursorModeShape.generated.swift
Normal file
27
NvimView/NvimView/NvimCursorModeShape.generated.swift
Normal 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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9cfd2a5d30525406eb4326171a7d43641105bea0d11eebea2bd161186c459929
|
||||
oid sha256:d26911f127c071ad3614ffe5506cb48eb018ebf4f203e528e5ca3be5648eebad
|
||||
size 71680
|
||||
|
4
NvimView/third-party/libintl/lib/libintl.a
vendored
4
NvimView/third-party/libintl/lib/libintl.a
vendored
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:14bcee7757d7dfa751eb33c554a1c3b6230ae9fe4e9dd5a22d5a238aaa1036bd
|
||||
size 100832
|
||||
oid sha256:da69917872f71d621ac0083cb03b7bd585ef7d8c7ac8e8c709569e3eaa049aae
|
||||
size 100824
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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}}\
|
||||
|
@ -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"/>
|
||||
|
@ -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"
|
||||
|
38
VimR/VimR/ConditionVariable.swift
Normal file
38
VimR/VimR/ConditionVariable.swift
Normal 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()
|
||||
}
|
118
VimR/VimR/CoreDataStack.swift
Normal file
118
VimR/VimR/CoreDataStack.swift
Normal 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)
|
||||
}
|
@ -16,6 +16,7 @@ struct Defs {
|
||||
|
||||
static let uiComponents = "ui-components"
|
||||
static let middleware = "middleware"
|
||||
static let service = "service"
|
||||
}
|
||||
|
||||
static let webViewProcessPool = WKProcessPool()
|
||||
|
21
VimR/VimR/FileItem+CoreDataClass.h
Normal file
21
VimR/VimR/FileItem+CoreDataClass.h
Normal 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"
|
14
VimR/VimR/FileItem+CoreDataClass.m
Normal file
14
VimR/VimR/FileItem+CoreDataClass.m
Normal 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
|
39
VimR/VimR/FileItem+CoreDataProperties.h
Normal file
39
VimR/VimR/FileItem+CoreDataProperties.h
Normal 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
|
27
VimR/VimR/FileItem+CoreDataProperties.m
Normal file
27
VimR/VimR/FileItem+CoreDataProperties.m
Normal 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
|
@ -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 }
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
23
VimR/VimR/FileScanBaton.h
Normal 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
205
VimR/VimR/FileScanBaton.m
Normal 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
|
||||
|
13
VimR/VimR/FoundationCommons.h
Normal file
13
VimR/VimR/FoundationCommons.h
Normal 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
|
40
VimR/VimR/FoundationCommons.m
Normal file
40
VimR/VimR/FoundationCommons.m
Normal 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
|
@ -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
|
||||
|
18
VimR/VimR/FuzzyMatcher/FuzzyMatcher.h
Normal file
18
VimR/VimR/FuzzyMatcher/FuzzyMatcher.h
Normal 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
|
33
VimR/VimR/FuzzyMatcher/FuzzyMatcher.mm
Normal file
33
VimR/VimR/FuzzyMatcher/FuzzyMatcher.mm
Normal 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
|
58
VimR/VimR/FuzzyMatcher/FuzzyMatcherPool.swift
Normal file
58
VimR/VimR/FuzzyMatcher/FuzzyMatcherPool.swift
Normal 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()
|
||||
}
|
||||
}
|
191
VimR/VimR/FuzzyMatcher/fuzzy_match.cc
Normal file
191
VimR/VimR/FuzzyMatcher/fuzzy_match.cc
Normal 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
|
34
VimR/VimR/FuzzyMatcher/fuzzy_match.hh
Normal file
34
VimR/VimR/FuzzyMatcher/fuzzy_match.hh
Normal 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
|
24
VimR/VimR/FuzzySearch.xcdatamodel/contents
Normal file
24
VimR/VimR/FuzzySearch.xcdatamodel/contents
Normal 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>
|
49
VimR/VimR/FuzzySearchFileMonitor.swift
Normal file
49
VimR/VimR/FuzzySearchFileMonitor.swift
Normal 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)
|
457
VimR/VimR/FuzzySearchService.swift
Normal file
457
VimR/VimR/FuzzySearchService.swift
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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/Wagner–Fischer_algorithm
|
||||
static func wagnerFisherDistance(_ target: String, pattern: String) -> Int {
|
||||
let s = target.unicodeScalars
|
||||
let t = pattern.unicodeScalars
|
||||
|
||||
let m = s.count
|
||||
|
||||
var prevRow = Array(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]
|
||||
}
|
||||
}
|
@ -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
|
@ -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)
|
||||
|
||||
|
@ -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) }
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
23
VimR/VimR/ScoredUrl.h
Normal 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
62
VimR/VimR/ScoredUrl.m
Normal 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
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
@ -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)))
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
60
bin/generate_cursor_shape.py
Executable 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())
|
@ -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
7
ci/README.md
Normal 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"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Auto generated for nvim ${version}
|
||||
// See bin/generate_autocmds.sh
|
||||
// See bin/generate_autocmds.py
|
||||
|
||||
enum NvimAutoCommandEvent: Int {
|
||||
|
||||
|
8
resources/cursor_shape.template.swift
Normal file
8
resources/cursor_shape.template.swift
Normal file
@ -0,0 +1,8 @@
|
||||
// Auto generated for nvim ${version}
|
||||
// See bin/generate_cursor_shape.py
|
||||
|
||||
public enum CursorModeShape: UInt {
|
||||
|
||||
${cursor_shapes}
|
||||
}
|
||||
|
@ -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
120
third-party/libag/include/config.h
vendored
Normal 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
26
third-party/libag/include/decompress.h
vendored
Normal 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
48
third-party/libag/include/ignore.h
vendored
Normal 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
36
third-party/libag/include/lang.h
vendored
Normal 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
32
third-party/libag/include/log.h
vendored
Normal 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
105
third-party/libag/include/options.h
vendored
Normal 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
26
third-party/libag/include/print.h
vendored
Normal 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
20
third-party/libag/include/scandir.h
vendored
Normal 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
78
third-party/libag/include/search.h
vendored
Normal 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
971
third-party/libag/include/uthash.h
vendored
Normal 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
119
third-party/libag/include/util.h
vendored
Normal 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
3
third-party/libag/lib/libag.a
vendored
Normal 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
677
third-party/libpcre/include/pcre.h
vendored
Normal 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 */
|
172
third-party/libpcre/include/pcre_scanner.h
vendored
Normal file
172
third-party/libpcre/include/pcre_scanner.h
vendored
Normal 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 */
|
180
third-party/libpcre/include/pcre_stringpiece.h
vendored
Normal file
180
third-party/libpcre/include/pcre_stringpiece.h
vendored
Normal 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
710
third-party/libpcre/include/pcrecpp.h
vendored
Normal 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
174
third-party/libpcre/include/pcrecpparg.h
vendored
Normal 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
146
third-party/libpcre/include/pcreposix.h
vendored
Normal 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
Loading…
Reference in New Issue
Block a user