swiftgemtext

[ACTIVE] gemtext parsing in swift
git clone git://git.figbert.com/swiftgemtext.git
Log | Files | Refs | README

commit c98a3bf0c627123a55e70370d034620cb6e65a7a
Author: FIGBERT <figbert@figbert.com>
Date:   Mon, 19 Apr 2021 16:36:36 -0700

Initial commit

Diffstat:
A.gitignore | 5+++++
A.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata | 7+++++++
APackage.swift | 21+++++++++++++++++++++
AREADME.md | 3+++
ASources/SwiftGemtext/SwiftGemtext.swift | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ATests/LinuxMain.swift | 7+++++++
ATests/SwiftGemtextTests/SwiftGemtextTests.swift | 15+++++++++++++++
ATests/SwiftGemtextTests/XCTestManifests.swift | 9+++++++++
8 files changed, 146 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:"> + </FileRef> +</Workspace> diff --git a/Package.swift b/Package.swift @@ -0,0 +1,21 @@ +// swift-tools-version:5.3 + +import PackageDescription + +let package = Package( + name: "SwiftGemtext", + products: [ + .library( + name: "SwiftGemtext", + targets: ["SwiftGemtext"]), + ], + dependencies: [], + targets: [ + .target( + name: "SwiftGemtext", + dependencies: []), + .testTarget( + name: "SwiftGemtextTests", + dependencies: ["SwiftGemtext"]), + ] +) diff --git a/README.md b/README.md @@ -0,0 +1,3 @@ +# SwiftGemtext + +A description of this package. diff --git a/Sources/SwiftGemtext/SwiftGemtext.swift b/Sources/SwiftGemtext/SwiftGemtext.swift @@ -0,0 +1,79 @@ +import SwiftUI + +struct SwiftGemtext { + let source: String + + init(_ src: String) { + self.source = src + } + + func parse() -> [LineType] { + var lines = [LineType]() + var pre = false + for line in source.lines { + let ln = String(line) + if pre { + if ln.starts(with: "```") { + lines.append(LineType.PreformattingToggle(nil)) + pre.toggle() + } else { + lines.append(LineType.PreformattedText(ln)) + } + } else { + if ln.starts(with: "```") { + let alt = ln.dropFirst(3).trimmingCharacters(in: .whitespacesAndNewlines) + lines.append(LineType.PreformattingToggle(alt.count > 0 ? alt : nil)) + pre.toggle() + } else { + lines.append(parsePlainLine(ln)) + } + } + } + return lines + } + + func parsePlainLine(_ line: String) -> LineType { + if line.starts(with: "#") { // Heading + var level: Int = 1 + if line.starts(with: "###") { + level = 3 + } else if line.starts(with: "##") { + level = 2 + } + return LineType.Heading(level, line.dropFirst(level).trimmingCharacters(in: .whitespacesAndNewlines)) + } else if line.starts(with: "=>") { // Link + let urlAndCaption = line.dropFirst(2).trimmingCharacters(in: .whitespacesAndNewlines) + let delim = urlAndCaption.firstIndex(of: " ")! + let url = URL(string: String(urlAndCaption[..<delim]))! + let caption = urlAndCaption[delim...] + if caption.count > 0 { + return LineType.Link(url, String(caption)) + } else { + return LineType.Link(url, nil) + } + } else if line.starts(with: "* ") { // Unordered List + return LineType.UnorderedList(line.dropFirst(2).trimmingCharacters(in: .whitespacesAndNewlines)) + } else if line.starts(with: ">") { // Quote + return LineType.Quote(String(line)) + } else if line.trimmingCharacters(in: .whitespacesAndNewlines) == "" { // Empty Line + return LineType.EmptyLine + } else { + return LineType.Text(line) + } + } +} + +enum LineType { + case Text(String) + case Link(URL, String?) + case PreformattingToggle(String?) + case PreformattedText(String) + case Heading(Int, String) + case UnorderedList(String) + case Quote(String) + case EmptyLine +} + +extension StringProtocol { + var lines: [SubSequence] { split(whereSeparator: \.isNewline) } +} diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift @@ -0,0 +1,7 @@ +import XCTest + +import SwiftGemtextTests + +var tests = [XCTestCaseEntry]() +tests += SwiftGemtextTests.allTests() +XCTMain(tests) diff --git a/Tests/SwiftGemtextTests/SwiftGemtextTests.swift b/Tests/SwiftGemtextTests/SwiftGemtextTests.swift @@ -0,0 +1,15 @@ +import XCTest +@testable import SwiftGemtext + +final class SwiftGemtextTests: XCTestCase { + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(SwiftGemtext().text, "Hello, World!") + } + + static var allTests = [ + ("testExample", testExample), + ] +} diff --git a/Tests/SwiftGemtextTests/XCTestManifests.swift b/Tests/SwiftGemtextTests/XCTestManifests.swift @@ -0,0 +1,9 @@ +import XCTest + +#if !canImport(ObjectiveC) +public func allTests() -> [XCTestCaseEntry] { + return [ + testCase(SwiftGemtextTests.allTests), + ] +} +#endif