Add GeminiFormat framework
This commit is contained in:
parent
ef03073d58
commit
a84a223c68
|
@ -12,8 +12,59 @@
|
|||
D626646324BBF1C300DF9B88 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D626646224BBF1C300DF9B88 /* Assets.xcassets */; };
|
||||
D626646624BBF1C300DF9B88 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D626646524BBF1C300DF9B88 /* Preview Assets.xcassets */; };
|
||||
D626646924BBF1C300DF9B88 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D626646724BBF1C300DF9B88 /* Main.storyboard */; };
|
||||
D62664B124BBF26A00DF9B88 /* GeminiFormat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D62664A824BBF26A00DF9B88 /* GeminiFormat.framework */; };
|
||||
D62664B824BBF26A00DF9B88 /* GeminiFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62664B724BBF26A00DF9B88 /* GeminiFormatTests.swift */; };
|
||||
D62664BA24BBF26A00DF9B88 /* GeminiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = D62664AA24BBF26A00DF9B88 /* GeminiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D62664BD24BBF26A00DF9B88 /* GeminiFormat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D62664A824BBF26A00DF9B88 /* GeminiFormat.framework */; };
|
||||
D62664BE24BBF26A00DF9B88 /* GeminiFormat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D62664A824BBF26A00DF9B88 /* GeminiFormat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
D62664C624BBF27300DF9B88 /* GeminiParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62664C524BBF27300DF9B88 /* GeminiParser.swift */; };
|
||||
D62664C824BBF2C600DF9B88 /* Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62664C724BBF2C600DF9B88 /* Document.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
D626648324BBF22E00DF9B88 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D626645324BBF1C200DF9B88 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D626645A24BBF1C200DF9B88;
|
||||
remoteInfo = Gemini;
|
||||
};
|
||||
D62664B224BBF26A00DF9B88 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D626645324BBF1C200DF9B88 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D62664A724BBF26A00DF9B88;
|
||||
remoteInfo = GeminiFormat;
|
||||
};
|
||||
D62664B424BBF26A00DF9B88 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D626645324BBF1C200DF9B88 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D626645A24BBF1C200DF9B88;
|
||||
remoteInfo = Gemini;
|
||||
};
|
||||
D62664BB24BBF26A00DF9B88 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D626645324BBF1C200DF9B88 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D62664A724BBF26A00DF9B88;
|
||||
remoteInfo = GeminiFormat;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
D626649124BBF22E00DF9B88 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
D62664BE24BBF26A00DF9B88 /* GeminiFormat.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
D626645B24BBF1C200DF9B88 /* Gemini.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Gemini.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D626645E24BBF1C200DF9B88 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
|
@ -23,6 +74,14 @@
|
|||
D626646824BBF1C300DF9B88 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
D626646A24BBF1C300DF9B88 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D626646B24BBF1C300DF9B88 /* Gemini.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Gemini.entitlements; sourceTree = "<group>"; };
|
||||
D62664A824BBF26A00DF9B88 /* GeminiFormat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GeminiFormat.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D62664AA24BBF26A00DF9B88 /* GeminiFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeminiFormat.h; sourceTree = "<group>"; };
|
||||
D62664AB24BBF26A00DF9B88 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D62664B024BBF26A00DF9B88 /* GeminiFormatTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GeminiFormatTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D62664B724BBF26A00DF9B88 /* GeminiFormatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeminiFormatTests.swift; sourceTree = "<group>"; };
|
||||
D62664B924BBF26A00DF9B88 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D62664C524BBF27300DF9B88 /* GeminiParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeminiParser.swift; sourceTree = "<group>"; };
|
||||
D62664C724BBF2C600DF9B88 /* Document.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Document.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -30,6 +89,19 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D62664BD24BBF26A00DF9B88 /* GeminiFormat.framework in Frameworks */,
|
||||
D62664A524BBF26A00DF9B88 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D62664AD24BBF26A00DF9B88 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D62664B124BBF26A00DF9B88 /* GeminiFormat.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -40,6 +112,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D626645D24BBF1C200DF9B88 /* Gemini */,
|
||||
D62664A924BBF26A00DF9B88 /* GeminiFormat */,
|
||||
D62664B624BBF26A00DF9B88 /* GeminiFormatTests */,
|
||||
D626645C24BBF1C200DF9B88 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
|
@ -48,6 +122,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D626645B24BBF1C200DF9B88 /* Gemini.app */,
|
||||
D62664A824BBF26A00DF9B88 /* GeminiFormat.framework */,
|
||||
D62664B024BBF26A00DF9B88 /* GeminiFormatTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
@ -74,8 +150,39 @@
|
|||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D62664A924BBF26A00DF9B88 /* GeminiFormat */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D62664AA24BBF26A00DF9B88 /* GeminiFormat.h */,
|
||||
D62664AB24BBF26A00DF9B88 /* Info.plist */,
|
||||
D62664C724BBF2C600DF9B88 /* Document.swift */,
|
||||
D62664C524BBF27300DF9B88 /* GeminiParser.swift */,
|
||||
);
|
||||
path = GeminiFormat;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D62664B624BBF26A00DF9B88 /* GeminiFormatTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D62664B724BBF26A00DF9B88 /* GeminiFormatTests.swift */,
|
||||
D62664B924BBF26A00DF9B88 /* Info.plist */,
|
||||
);
|
||||
path = GeminiFormatTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
D62664A324BBF26A00DF9B88 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D62664BA24BBF26A00DF9B88 /* GeminiFormat.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
D626645A24BBF1C200DF9B88 /* Gemini */ = {
|
||||
isa = PBXNativeTarget;
|
||||
|
@ -88,12 +195,50 @@
|
|||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
D62664BC24BBF26A00DF9B88 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Gemini;
|
||||
productName = Gemini;
|
||||
productReference = D626645B24BBF1C200DF9B88 /* Gemini.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
D62664A724BBF26A00DF9B88 /* GeminiFormat */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D62664BF24BBF26A00DF9B88 /* Build configuration list for PBXNativeTarget "GeminiFormat" */;
|
||||
buildPhases = (
|
||||
D62664A324BBF26A00DF9B88 /* Headers */,
|
||||
D62664A424BBF26A00DF9B88 /* Sources */,
|
||||
D62664A524BBF26A00DF9B88 /* Frameworks */,
|
||||
D62664A624BBF26A00DF9B88 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = GeminiFormat;
|
||||
productName = GeminiFormat;
|
||||
productReference = D62664A824BBF26A00DF9B88 /* GeminiFormat.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
D62664AF24BBF26A00DF9B88 /* GeminiFormatTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D62664C224BBF26A00DF9B88 /* Build configuration list for PBXNativeTarget "GeminiFormatTests" */;
|
||||
buildPhases = (
|
||||
D62664AC24BBF26A00DF9B88 /* Sources */,
|
||||
D62664AD24BBF26A00DF9B88 /* Frameworks */,
|
||||
D62664AE24BBF26A00DF9B88 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
D62664B324BBF26A00DF9B88 /* PBXTargetDependency */,
|
||||
D62664B524BBF26A00DF9B88 /* PBXTargetDependency */,
|
||||
);
|
||||
name = GeminiFormatTests;
|
||||
productName = GeminiFormatTests;
|
||||
productReference = D62664B024BBF26A00DF9B88 /* GeminiFormatTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
|
@ -106,6 +251,14 @@
|
|||
D626645A24BBF1C200DF9B88 = {
|
||||
CreatedOnToolsVersion = 12.0;
|
||||
};
|
||||
D62664A724BBF26A00DF9B88 = {
|
||||
CreatedOnToolsVersion = 12.0;
|
||||
LastSwiftMigration = 1200;
|
||||
};
|
||||
D62664AF24BBF26A00DF9B88 = {
|
||||
CreatedOnToolsVersion = 12.0;
|
||||
TestTargetID = D626645A24BBF1C200DF9B88;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = D626645624BBF1C200DF9B88 /* Build configuration list for PBXProject "Gemini" */;
|
||||
|
@ -122,6 +275,8 @@
|
|||
projectRoot = "";
|
||||
targets = (
|
||||
D626645A24BBF1C200DF9B88 /* Gemini */,
|
||||
D62664A724BBF26A00DF9B88 /* GeminiFormat */,
|
||||
D62664AF24BBF26A00DF9B88 /* GeminiFormatTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
@ -137,6 +292,20 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D62664A624BBF26A00DF9B88 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D62664AE24BBF26A00DF9B88 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
@ -149,8 +318,43 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D62664A424BBF26A00DF9B88 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D62664C824BBF2C600DF9B88 /* Document.swift in Sources */,
|
||||
D62664C624BBF27300DF9B88 /* GeminiParser.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D62664AC24BBF26A00DF9B88 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D62664B824BBF26A00DF9B88 /* GeminiFormatTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
D62664B324BBF26A00DF9B88 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D62664A724BBF26A00DF9B88 /* GeminiFormat */;
|
||||
targetProxy = D62664B224BBF26A00DF9B88 /* PBXContainerItemProxy */;
|
||||
};
|
||||
D62664B524BBF26A00DF9B88 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D626645A24BBF1C200DF9B88 /* Gemini */;
|
||||
targetProxy = D62664B424BBF26A00DF9B88 /* PBXContainerItemProxy */;
|
||||
};
|
||||
D62664BC24BBF26A00DF9B88 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D62664A724BBF26A00DF9B88 /* GeminiFormat */;
|
||||
targetProxy = D62664BB24BBF26A00DF9B88 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
D626646724BBF1C300DF9B88 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
|
@ -281,6 +485,7 @@
|
|||
D626646F24BBF1C300DF9B88 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = Gemini/Gemini.entitlements;
|
||||
|
@ -305,6 +510,7 @@
|
|||
D626647024BBF1C300DF9B88 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = Gemini/Gemini.entitlements;
|
||||
|
@ -326,6 +532,105 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
D62664C024BBF26A00DF9B88 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = HGYVAQA9FW;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = GeminiFormat/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.GeminiFormat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D62664C124BBF26A00DF9B88 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = HGYVAQA9FW;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = GeminiFormat/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.GeminiFormat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D62664C324BBF26A00DF9B88 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = HGYVAQA9FW;
|
||||
INFOPLIST_FILE = GeminiFormatTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.GeminiFormatTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Gemini.app/Contents/MacOS/Gemini";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D62664C424BBF26A00DF9B88 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = HGYVAQA9FW;
|
||||
INFOPLIST_FILE = GeminiFormatTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.GeminiFormatTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Gemini.app/Contents/MacOS/Gemini";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
|
@ -347,6 +652,24 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D62664BF24BBF26A00DF9B88 /* Build configuration list for PBXNativeTarget "GeminiFormat" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D62664C024BBF26A00DF9B88 /* Debug */,
|
||||
D62664C124BBF26A00DF9B88 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D62664C224BBF26A00DF9B88 /* Build configuration list for PBXNativeTarget "GeminiFormatTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D62664C324BBF26A00DF9B88 /* Debug */,
|
||||
D62664C424BBF26A00DF9B88 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = D626645324BBF1C200DF9B88 /* Project object */;
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>GeminiFormat.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// Document.swift
|
||||
// GeminiFormat
|
||||
//
|
||||
// Created by Shadowfacts on 7/12/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Document {
|
||||
let url: URL
|
||||
var lines: [Line]
|
||||
|
||||
init(url: URL, lines: [Line] = []) {
|
||||
self.url = url
|
||||
self.lines = lines
|
||||
}
|
||||
}
|
||||
|
||||
extension Document {
|
||||
enum Line: Equatable {
|
||||
case text(String)
|
||||
case link(URL, text: String?)
|
||||
case preformattedText(String, alt: String?)
|
||||
case heading(String, level: HeadingLevel)
|
||||
case unorderedListItem(String)
|
||||
case quote(String)
|
||||
}
|
||||
}
|
||||
|
||||
extension Document {
|
||||
enum HeadingLevel: Int {
|
||||
case h1 = 1, h2 = 2, h3 = 3
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// GeminiFormat.h
|
||||
// GeminiFormat
|
||||
//
|
||||
// Created by Shadowfacts on 7/12/20.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for GeminiFormat.
|
||||
FOUNDATION_EXPORT double GeminiFormatVersionNumber;
|
||||
|
||||
//! Project version string for GeminiFormat.
|
||||
FOUNDATION_EXPORT const unsigned char GeminiFormatVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <GeminiFormat/PublicHeader.h>
|
||||
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
//
|
||||
// GeminiParser.swift
|
||||
// GeminiFormat
|
||||
//
|
||||
// Created by Shadowfacts on 7/12/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct GeminiParser {
|
||||
|
||||
private init() {}
|
||||
|
||||
static func parse(text: String, baseURL: URL) -> Document {
|
||||
var doc = Document(url: baseURL)
|
||||
|
||||
var preformattingState = PreformattingState.off
|
||||
text.enumerateLines { (line, stop) in
|
||||
if line.starts(with: "```") {
|
||||
switch preformattingState {
|
||||
case .off:
|
||||
let alt: String?
|
||||
if line.count > 3 {
|
||||
alt = String(line[line.index(line.startIndex, offsetBy: 3)...])
|
||||
} else {
|
||||
alt = nil
|
||||
}
|
||||
preformattingState = .on(alt)
|
||||
case .on(_):
|
||||
preformattingState = .off
|
||||
}
|
||||
if case .off = preformattingState {
|
||||
|
||||
}
|
||||
} else if case let .on(alt) = preformattingState {
|
||||
doc.lines.append(.preformattedText(line, alt: alt))
|
||||
} else if line.starts(with: "=>") {
|
||||
// Link line
|
||||
let urlStart = line.firstNonWhitespaceIndex(after: line.index(line.startIndex, offsetBy: 2))
|
||||
let urlEnd = line.firstWhitespaceIndex(after: urlStart)
|
||||
let textStart = line.firstNonWhitespaceIndex(after: urlEnd)
|
||||
|
||||
let urlString = String(line[urlStart..<urlEnd])
|
||||
// todo: if the URL initializer fails, should there be a .link line with a nil URL?
|
||||
let url = URL(string: urlString, relativeTo: baseURL)!.absoluteURL
|
||||
|
||||
let text: String?
|
||||
if textStart < line.endIndex {
|
||||
text = String(line[textStart..<line.endIndex])
|
||||
} else {
|
||||
text = nil
|
||||
}
|
||||
|
||||
doc.lines.append(.link(url, text: text))
|
||||
} else if line.starts(with: "#") {
|
||||
let level: Document.HeadingLevel
|
||||
if line.starts(with: "###") {
|
||||
level = .h3
|
||||
} else if line.starts(with: "##") {
|
||||
level = .h2
|
||||
} else {
|
||||
level = .h1
|
||||
}
|
||||
let headingStart = line.firstNonWhitespaceIndex(after: line.index(line.startIndex, offsetBy: level.rawValue))
|
||||
let headingText = String(line[headingStart...])
|
||||
doc.lines.append(.heading(headingText, level: level))
|
||||
} else if line.starts(with: "* ") {
|
||||
let listItemStart = line.firstNonWhitespaceIndex(after: line.index(line.startIndex, offsetBy: 2))
|
||||
let listItemText = String(line[listItemStart...])
|
||||
doc.lines.append(.unorderedListItem(listItemText))
|
||||
} else if line.starts(with: ">") {
|
||||
let quoteStartIndex = line.firstNonWhitespaceIndex(after: line.index(after: line.startIndex))
|
||||
let quoteText = String(line[quoteStartIndex...])
|
||||
doc.lines.append(.quote(quoteText))
|
||||
} else {
|
||||
doc.lines.append(.text(line))
|
||||
}
|
||||
}
|
||||
|
||||
return doc
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fileprivate extension GeminiParser {
|
||||
enum PreformattingState {
|
||||
case off
|
||||
case on(_ alt: String?)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension String {
|
||||
func firstNonWhitespaceIndex(after index: String.Index) -> String.Index {
|
||||
var index = index
|
||||
// using .unicodeScalars.first should be fine, since all whitespace characters are single scalars
|
||||
while index < self.endIndex, CharacterSet.whitespaces.contains(self[index].unicodeScalars.first!) {
|
||||
index = self.index(after: index)
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
func firstWhitespaceIndex(after index: String.Index) -> String.Index {
|
||||
var index = index
|
||||
// todo: could the first unicode scalar of a character be whitespace even though the whole character is not?
|
||||
while index < self.endIndex, !CharacterSet.whitespaces.contains(self[index].unicodeScalars.first!) {
|
||||
index = self.index(after: index)
|
||||
}
|
||||
return index
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,114 @@
|
|||
//
|
||||
// GeminiFormatTests.swift
|
||||
// GeminiFormatTests
|
||||
//
|
||||
// Created by Shadowfacts on 7/12/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import GeminiFormat
|
||||
|
||||
class GeminiFormatTests: XCTestCase {
|
||||
|
||||
func assertParseLines(text: String, lines expected: [Document.Line], message: String, file: StaticString = #filePath, line: UInt = #line) {
|
||||
let doc = GeminiParser.parse(text: text, baseURL: URL(string: "gemini://example.com")!)
|
||||
XCTAssertEqual(doc.lines, expected, message, file: file, line: line)
|
||||
}
|
||||
|
||||
func testParsePlainLines() {
|
||||
assertParseLines(text: "test", lines: [.text("test")], message: "parse a plain text line")
|
||||
assertParseLines(text: "one\ntwo", lines: [
|
||||
.text("one"),
|
||||
.text("two")
|
||||
], message: "parse multiple, newline delmited plain lines")
|
||||
assertParseLines(text: "one\r\ntwo", lines: [
|
||||
.text("one"),
|
||||
.text("two")
|
||||
], message: "parse multiple, CRLF delmited plain lines")
|
||||
}
|
||||
|
||||
func testParseLinkLines() {
|
||||
assertParseLines(text: "=> gemini://blah.com", lines: [
|
||||
.link(URL(string: "gemini://blah.com")!, text: nil)
|
||||
], message: "parse a bare link line")
|
||||
assertParseLines(text: "=> gemini://blah.com:1234/foo/bar?baz", lines: [
|
||||
.link(URL(string: "gemini://blah.com:1234/foo/bar?baz")!, text: nil)
|
||||
], message: "parse a more complex bare link line")
|
||||
assertParseLines(text: "=> gemini://blah.com \t Link to example", lines: [
|
||||
.link(URL(string: "gemini://blah.com")!, text: "Link to example")
|
||||
], message: "parse a simple link line with associated text")
|
||||
assertParseLines(text: "=> gemini://blah.com/foo Link to foo", lines: [
|
||||
.link(URL(string: "gemini://blah.com/foo")!, text: "Link to foo")
|
||||
], message: "parse a more complex link line with associated text")
|
||||
assertParseLines(text: "=> https://example.com", lines: [
|
||||
.link(URL(string: "https://example.com")!, text: nil)
|
||||
], message: "parse a link with a different protocol")
|
||||
assertParseLines(text: "=> /foo/bar/baz", lines: [
|
||||
.link(URL(string: "gemini://example.com/foo/bar/baz")!, text: nil)
|
||||
], message: "resolve a relative path link")
|
||||
assertParseLines(text: "=>gemini://blah.com", lines: [
|
||||
.link(URL(string: "gemini://blah.com")!, text: nil)
|
||||
], message: "parse link without whitespace after =>")
|
||||
}
|
||||
|
||||
func testParseHeadingLines() {
|
||||
assertParseLines(text: "# test", lines: [
|
||||
.heading("test", level: .h1)
|
||||
], message: "level 1 heading")
|
||||
assertParseLines(text: "#test", lines: [
|
||||
.heading("test", level: .h1)
|
||||
], message: "level 1 heading without whitespace")
|
||||
assertParseLines(text: "#test\n## two\r\n###three", lines: [
|
||||
.heading("test", level: .h1),
|
||||
.heading("two", level: .h2),
|
||||
.heading("three", level: .h3)
|
||||
], message: "multiples headings with and without whitespace")
|
||||
}
|
||||
|
||||
func testParseListItemLines() {
|
||||
assertParseLines(text: "* test list item", lines: [
|
||||
.unorderedListItem("test list item")
|
||||
], message: "parse simple list item")
|
||||
assertParseLines(text: "*test", lines: [
|
||||
.text("*test")
|
||||
], message: "don't parse list item without space after asterisk")
|
||||
assertParseLines(text: "* one\n* two\n*three", lines: [
|
||||
.unorderedListItem("one"),
|
||||
.unorderedListItem("two"),
|
||||
.text("*three")
|
||||
], message: "parse multiple list items")
|
||||
}
|
||||
|
||||
func testParseQuoteLines() {
|
||||
assertParseLines(text: "> quote", lines: [
|
||||
.quote("quote")
|
||||
], message: "parse quote line")
|
||||
assertParseLines(text: ">quote", lines: [
|
||||
.quote("quote")
|
||||
], message: "parse quote line without space after >")
|
||||
assertParseLines(text: ">one\n> two\n>three", lines: [
|
||||
.quote("one"),
|
||||
.quote("two"),
|
||||
.quote("three")
|
||||
], message: "parse multiple quote lines")
|
||||
}
|
||||
|
||||
func testParsePreformattedLines() {
|
||||
assertParseLines(text: "```\nsomething\n```", lines: [
|
||||
.preformattedText("something", alt: nil)
|
||||
], message: "parse simple preformatted line")
|
||||
assertParseLines(text: "```alt\nsomething\n```", lines: [
|
||||
.preformattedText("something", alt: "alt")
|
||||
], message: "parse simple preformatted line with alt")
|
||||
assertParseLines(text: "```alt\nsomething\n```other", lines: [
|
||||
.preformattedText("something", alt: "alt")
|
||||
], message: "ignore extra text after closing ```")
|
||||
assertParseLines(text: "```\n# not a heading\n* not a list item\n>not a quote\n=> /link not a link\n```", lines: [
|
||||
.preformattedText("# not a heading", alt: nil),
|
||||
.preformattedText("* not a list item", alt: nil),
|
||||
.preformattedText(">not a quote", alt: nil),
|
||||
.preformattedText("=> /link not a link", alt: nil),
|
||||
], message: "don't parse special lines inside preformatted")
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
Loading…
Reference in New Issue