Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Custom list prefixes for AttributedStringVisitor #255

Merged
merged 2 commits into from Apr 28, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions Down.xcodeproj/project.pbxproj
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
14C5E33521877CE900D5380C /* DownView.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D41689B51CFFE6BB00E5802B /* DownView.bundle */; };
26CABB93252B4D490032183C /* ChildSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26CABB92252B4D490032183C /* ChildSequence.swift */; };
6A66ABDE262E082C007C65CA /* ListItemPrefixGeneratorBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A66ABDD262E082C007C65CA /* ListItemPrefixGeneratorBuilder.swift */; };
8A569F481E6B3ED2008BE2AC /* DownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43AE5D91CFFD0D0006E1522 /* DownView.swift */; };
8A569F491E6B3ED9008BE2AC /* blocks.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EF71CFA5D63008EEC6E /* blocks.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
8A569F4A1E6B3ED9008BE2AC /* buffer.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201EF81CFA5D63008EEC6E /* buffer.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; };
Expand Down Expand Up @@ -201,6 +202,7 @@
/* Begin PBXFileReference section */
14C5E33621877FCD00D5380C /* DownView (macOS).bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = "DownView (macOS).bundle"; sourceTree = "<group>"; };
26CABB92252B4D490032183C /* ChildSequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChildSequence.swift; sourceTree = "<group>"; };
6A66ABDD262E082C007C65CA /* ListItemPrefixGeneratorBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemPrefixGeneratorBuilder.swift; sourceTree = "<group>"; };
8A569F401E6B3E50008BE2AC /* Down.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Down.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8AFAEAFB1E6E32E900E09B68 /* DownTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DownTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8C73B9B522A687C400C8E60F /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
Expand Down Expand Up @@ -712,6 +714,7 @@
children = (
EEEBEE71225D2F9200AE438D /* AttributedStringVisitor.swift */,
EE8F38CD22BFEDE50056270E /* ListItemPrefixGenerator.swift */,
6A66ABDD262E082C007C65CA /* ListItemPrefixGeneratorBuilder.swift */,
EEEBEE6F225D2B9D00AE438D /* DebugVisitor.swift */,
EEF137702259E7E700D7DDE0 /* Visitor.swift */,
);
Expand Down Expand Up @@ -1002,6 +1005,7 @@
8A569F671E6B3ED9008BE2AC /* render.c in Sources */,
EEEBEE49225D29C200AE438D /* BlockQuote.swift in Sources */,
8A569F651E6B3ED9008BE2AC /* references.c in Sources */,
6A66ABDE262E082C007C65CA /* ListItemPrefixGeneratorBuilder.swift in Sources */,
EEEBEE67225D2AF900AE438D /* Emphasis.swift in Sources */,
EEA2BDCA22F7152B00D0C72C /* ThematicBreakOptions.swift in Sources */,
);
Expand Down
15 changes: 13 additions & 2 deletions Sources/Down/AST/Visitors/AttributedStringVisitor.swift
Expand Up @@ -20,17 +20,23 @@ public class AttributedStringVisitor {

private let styler: Styler
private let options: DownOptions
private let listPrefixGeneratorBuilder: ListItemPrefixGeneratorBuilder
dloic marked this conversation as resolved.
Show resolved Hide resolved
private var listPrefixGenerators = [ListItemPrefixGenerator]()

/// Creates a new instance with the given styler and options.
///
/// - parameters:
/// - styler: used to style the markdown elements.
/// - options: may be used to modify rendering.
/// - listPrefixGeneratorBuilder: may be used to modify list prefixes.

public init(styler: Styler, options: DownOptions = .default) {
public init(
styler: Styler,
options: DownOptions = .default,
listPrefixGeneratorBuilder: ListItemPrefixGeneratorBuilder = StaticListItemPrefixGeneratorBuilder()) {
dloic marked this conversation as resolved.
Show resolved Hide resolved
self.styler = styler
self.options = options
self.listPrefixGeneratorBuilder = listPrefixGeneratorBuilder
}

}
Expand All @@ -53,7 +59,12 @@ extension AttributedStringVisitor: Visitor {
}

public func visit(list node: List) -> NSMutableAttributedString {
listPrefixGenerators.append(ListItemPrefixGenerator(list: node))

listPrefixGenerators.append(
listPrefixGeneratorBuilder.build(
listType: node.listType,
numberOfItems: node.numberOfItems,
nestDepth: node.nestDepth))
dloic marked this conversation as resolved.
Show resolved Hide resolved
defer { listPrefixGenerators.removeLast() }

let items = visitChildren(of: node)
Expand Down
43 changes: 26 additions & 17 deletions Sources/Down/AST/Visitors/ListItemPrefixGenerator.swift
Expand Up @@ -8,34 +8,43 @@

import Foundation

class ListItemPrefixGenerator {
/// A ListItemPrefixGenerator is an object used to generate list item prefix.
///
/// ListItemPrefixGenerator are created by `ListItemPrefixGeneratorBuilder`, the later used in
/// conjunction with an instance of `AttributedStringVisitor`.
public protocol ListItemPrefixGenerator {
init(listType: List.ListType, numberOfItems: Int, nestDepth: Int)
func next() -> String?
}
dloic marked this conversation as resolved.
Show resolved Hide resolved

/// Default implementation of `ListItemPrefixGenerator`.
/// Generating the following symbol based on `List.ListType`:
/// - List.ListType is bullet => "•"
/// - List.ListType is ordered => "X." (where is the item number)
public class StaticListItemPrefixGenerator: ListItemPrefixGenerator {

// MARK: - Properties

private var prefixes: IndexingIterator<[String]>

// MARK: - Life cycle

convenience init(list: List) {
self.init(listType: list.listType, numberOfItems: list.numberOfItems)
}

init(listType: List.ListType, numberOfItems: Int) {
switch listType {
case .bullet:
prefixes = [String](repeating: "•", count: numberOfItems)
.makeIterator()

case .ordered(let start):
prefixes = (start..<(start + numberOfItems))
.map { "\($0)." }
.makeIterator()
required public init(listType: List.ListType, numberOfItems: Int, nestDepth: Int) {
switch listType {
case .bullet:
prefixes = [String](repeating: "•", count: numberOfItems)
.makeIterator()

case .ordered(let start):
prefixes = (start..<(start + numberOfItems))
.map { "\($0)." }
.makeIterator()
}
}
}

// MARK: - Methods

func next() -> String? {
public func next() -> String? {
prefixes.next()
}

Expand Down
25 changes: 25 additions & 0 deletions Sources/Down/AST/Visitors/ListItemPrefixGeneratorBuilder.swift
@@ -0,0 +1,25 @@
//
// ListItemPrefixGeneratorBuilder.swift
// Down
//
// Created by Loïc DARDANT on 2021-04-19.
// Copyright © 2021 Down. All rights reserved.
//

import Foundation

/// Builder of `ListItemPrefixGeneratorBuilder` used in `AttributedStringVisitor`.
/// Visitor is creating one ListItemPrefixGenerator per list.
public protocol ListItemPrefixGeneratorBuilder {
func build(listType: List.ListType, numberOfItems: Int, nestDepth: Int) -> ListItemPrefixGenerator
}

/// Default implementation of `StaticListItemPrefixGeneratorBuilder`, using `StaticListItemPrefixGenerator`.
public class StaticListItemPrefixGeneratorBuilder: ListItemPrefixGeneratorBuilder {

public init() {}

public func build(listType: List.ListType, numberOfItems: Int, nestDepth: Int) -> ListItemPrefixGenerator {
return StaticListItemPrefixGenerator(listType: listType, numberOfItems: numberOfItems, nestDepth: nestDepth)
}
}
8 changes: 4 additions & 4 deletions Tests/DownTests/AST/ListItemPrefixGeneratorTests.swift
Expand Up @@ -11,9 +11,9 @@ import XCTest

class ListItemPrefixGeneratorTests: XCTestCase {

func testNumberPrefixGeneration() {
func testNumberStaticPrefixGeneration() {
// Given
let sut = ListItemPrefixGenerator(listType: .ordered(start: 3), numberOfItems: 3)
let sut = StaticListItemPrefixGenerator(listType: .ordered(start: 3), numberOfItems: 3, nestDepth: 1)

// Then
XCTAssertEqual("3.", sut.next())
Expand All @@ -22,9 +22,9 @@ class ListItemPrefixGeneratorTests: XCTestCase {
XCTAssertNil(sut.next())
}

func testBulletPrefixGeneration() {
func testBulletStaticPrefixGeneration() {
// Given
let sut = ListItemPrefixGenerator(listType: .bullet, numberOfItems: 3)
let sut = StaticListItemPrefixGenerator(listType: .bullet, numberOfItems: 3, nestDepth: 1)

// Then
XCTAssertEqual("•", sut.next())
Expand Down