Maaku

Build Status Swift CocoaPods Compatible Carthage compatible Swift Package Manager compatible Platform

Maaku 框架提供了一个 Swift 包装器,围绕 cmark-gfm 构建,并添加了对 AST 的 Swift 友好的表示。 支持 gfm 扩展,包括表格、删除线、自动链接和标签过滤器。

Maaku 还支持插件约定,自定义渲染器可以使用该约定。 提供了一个插件作为示例。

TexturedMaaku 基于 Maaku 和 Texture 构建,提供了一个原生的 iOS CommonMark 渲染框架,使用 Swift 编写。

安装

CocoaPods

CocoaPods 是 Cocoa 项目的依赖管理器。 您可以使用以下命令安装它:

$ gem install cocoapods

要使用 CocoaPods 将 Maaku 集成到您的 Xcode 项目中,请在您的 Podfile 中指定它:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!

target '<Your Target Name>' do
    pod 'Maaku'
end

然后,运行以下命令:

$ pod install

Carthage

Carthage 是一个去中心化的依赖管理器,它可以构建您的依赖项并为您提供二进制框架。

您可以使用 Homebrew 安装 Carthage,使用以下命令:

$ brew update
$ brew install carthage

要使用 Carthage 将 Maaku 集成到您的 Xcode 项目中,请在您的 Cartfile 中指定它:

github "KristopherGBaker/Maaku" ~> 0.6.0

运行 carthage update 以构建框架,并将构建的 Maaku.framework 拖到您的 Xcode 项目中。

Swift Package Manager

Swift Package Manager 是一种用于自动化 Swift 代码分发的工具,并已集成到 swift 编译器中。 它还处于早期开发阶段,但 Maaku 确实支持在支持的平台上使用它。

一旦您设置好 Swift 包,添加 Maaku 作为依赖项就像将其添加到您的 Package.swiftdependencies 值一样简单。

dependencies: [
    .package(url: "https://github.com/KristopherGBaker/Maaku.git", from: "0.6.0")
]

使用 Swift PM 构建

构建 macOS 版本
$ swift build -Xswiftc "-target" -Xswiftc "x86_64-apple-macosx10.14"
运行测试
$ swift test -Xswiftc "-target" -Xswiftc "x86_64-apple-macosx10.14"

核心 (Core)

Document 是使用 Maaku 的主要接口。 可以通过传递表示 CommonMark 的 Data 或 String 来初始化 Document。

let document = try Document(text: commonMark)

初始化 Document 将解析 CommonMark 并创建一个您可以访问的 AST。 该文档包含顶级块元素列表,每个块元素可以包含其他块元素或内联元素。 块元素可以是容器块或叶块。 容器块可以包含其他块,而叶块不能。

样式 (Style)

采用 Node 协议的核心类型支持使用 attributedText 方法转换为 NSAttributedString (大多数类型都支持,但目前存在一些限制,特别是内联图像和 HTML - 包括内联和块)。

可以使用 Style 类型指定 attributedText 方法使用的字体和颜色。 Style 的默认实现由 DefaultStyle 提供。

CMark

CMark* 类型(部分受到 CocoaMarkdown 的启发)在 cmark-gfm 之上提供了一个 Swift 友好的接口。 只需在您的 Podfile 中包含 Maaku/CMark 子规范,即可单独使用 CMark 类型,而无需 Core。

插件 (Plugins)

插件遵循一种约定,即插件以 CommonMark 文本中的单个链接的形式出现。 这是一个 youtube 插件在 CommonMark 中可能显示的样子示例:

Some other markdown text.

[youtubevideo](https://youtu.be/kkdBB1hVLX0)

More markdown.

要添加对此插件的支持,我们需要实现两个协议:Plugin 和 PluginParser(在 Plugin.swift 中定义,并在下面显示以供参考)。

public protocol Plugin: LeafBlock {
    static var pluginName: PluginName { get }
}
public protocol PluginParser {
    var name: String { get }
    func parse(text: String) -> Plugin?
}

插件示例

Youtube 插件在框架中作为示例提供(如果您使用 CocoaPods 安装,则作为可选子规范)。

public struct YoutubePlugin: Plugin {

    public static let pluginName: PluginName = "youtubevideo"

    public let url: URL

    public var videoId: String? {
        return url.path.components(separatedBy: "/").last
    }

    public init(url: URL) {
        self.url = url
    }
}

pluginName 值对于插件应该是唯一的。 它可以与用于 PluginParser 的 name 相同,但不需要。

PluginParser 示例

public struct YoutubePluginParser: PluginParser {

    public let name = "youtubevideo"

    public func parse(text: String) -> Plugin? {
        guard let url = parseURL(text) else {
            return nil
        }

        return YoutubePlugin(url: url)
    }

    public init() {

    }
}

name 值应与您用于插件的链接文本匹配。 由于 Youtube 插件看起来像 [youtubevideo](https://youtu.be/kkdBB1hVLX0),因此 youtubevideo 用于 name

原始链接目标被传递给 parse 方法。 您可以决定如何处理文本值以初始化您的插件,但有可用的便捷方法可以简化此过程。

splitPluginParams 方法支持链接目标中多个插件参数的以下格式:

param1::value1|param2::value2|param3::value3

splitPluginParams 将以该格式拆分参数为一个字典,您可以使用该字典来初始化您的插件。

假设一个 Youtube 插件看起来像这样

[youtubevideo](source::https://youtu.be/kkdBB1hVLX0||caption::Checkout this video)

然后插件将更新为如下所示

public struct YoutubePlugin: Plugin {

    public static let pluginName: PluginName = "youtubevideo"

    public let url: URL
    
    public let caption: String?

    public var videoId: String? {
        return url.path.components(separatedBy: "/").last
    }

    public init(url: URL, caption: String?) {
        self.url = url
        self.caption = caption
    }
}

而 PluginParser 可能会看起来像

public struct YoutubePluginParser: PluginParser {

    public let name = "youtubevideo"

    public func parse(text: String) -> Plugin? {
        let parameters = splitPluginParams(text)
        
        guard parameters.count > 0,
            let source = parameters["source"],
            let url = URL(string: source) else {
            return nil
        }
        
        let caption = parameters["caption"]

        return YoutubePlugin(url: url, caption: caption)
    }

    public init() {

    }
}

注册插件

PluginParser 必须先在 PluginManager 中注册,然后才能被 Maaku 解析器使用。 如果您不注册插件,它将显示为 Link 或 Text 而不是 Plugin。

要注册 PluginParser,请初始化它并将其传递给 PluginManager.registerParsers

对于 Youtube 示例

PluginManager.registerParsers([YoutubePluginParser()])