johnxnguyen / Down

Blazing fast Markdown / CommonMark rendering in Swift, built upon cmark.
Other
2.24k stars 319 forks source link

[Feature] Custom list prefixes for AttributedStringVisitor #255

Closed dloic closed 3 years ago

dloic commented 3 years ago

After investigation, I've tried to find the least intrusive way to add the feature of custom list prefixes for AttributedStringVisitor. I've decided to go for ListItemPrefixgenerator changes, as fitting the feature in the styler was not possible.

The PR is not changing the current behavior, but opening a bit the API so one can provide another implementation. See below for an example:

Definition of a custom ListPrefixGenerator:

public class CustomListItemPrefixGeneratorBuilder: ListItemPrefixGeneratorBuilder {
    public func build(listType: List.ListType, numberOfItems: Int, nestDepth: Int) -> ListItemPrefixGenerator {
        return CustomListItemPrefixGenerator(listType: listType, numberOfItems: numberOfItems, nestDepth: nestDepth)
    }

}

public class CustomListItemPrefixGenerator: ListItemPrefixGenerator {

    private var prefixes: IndexingIterator<[String]>

    required public init(listType: List.ListType, numberOfItems: Int, nestDepth: Int) {

        switch listType {
        case .bullet:
            let prefix = CustomListItemPrefixGenerator.unorderedPrefix(nestDepth: nestDepth)
            prefixes = [String](repeating: prefix, count: numberOfItems)
                .makeIterator()

        case .ordered(let start):
            prefixes = (start..<(start + numberOfItems))
                .map { CustomListItemPrefixGenerator.orderedPrefix(value: $0, nestDepth: nestDepth) }
                .makeIterator()
        }
    }

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

    private static func unorderedPrefix(nestDepth: Int) -> String {
        switch nestDepth {
        case 0:
            return "●"
        case 1:
            return "○"
        case _ where nestDepth >= 2:
            return "▪︎"
        default:
            return "●"
        }
    }

    private static func orderedPrefix(value: Int, nestDepth: Int) -> String {
        switch value {
        case 1:
            return "1️⃣"
        case 2:
            return "2️⃣"
        case 3:
            return "3️⃣"
        default:
            return "🔢"
        }
    }
}

Usage:

let document = try! markdown.toDocument(.default)
let visitor = AttributedStringVisitor(
    styler: DownStyler(),
    options: .default,
    listPrefixGeneratorBuilder: CustomListItemPrefixGeneratorBuilder()
)
subview.attributedText = document.accept(visitor)

Render:

Capture d’écran, le 2021-04-19 à 15 47 27
codecov[bot] commented 3 years ago

Codecov Report

Merging #255 (71cd933) into master (2524b62) will increase coverage by 0.01%. The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #255      +/-   ##
==========================================
+ Coverage   91.29%   91.31%   +0.01%     
==========================================
  Files          60       60              
  Lines        1057     1059       +2     
==========================================
+ Hits          965      967       +2     
  Misses         92       92              
Impacted Files Coverage Δ
...es/Down/AST/Visitors/AttributedStringVisitor.swift 91.66% <100.00%> (+0.14%) :arrow_up:
...es/Down/AST/Visitors/ListItemPrefixGenerator.swift 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update 2524b62...71cd933. Read the comment docs.

dloic commented 3 years ago

Hi @johnxnguyen! Not sure who should be reviewing this one :)

I've checked the Travis CI build error, seems related to log file length, I cannot see the error. Do you confirm?

johnxnguyen commented 3 years ago

Hey @dloic , thanks for the PR! I'll try to take a look at this tonight and get back to you soon.

dloic commented 3 years ago

@johnxnguyen thanks a lot!

johnxnguyen commented 3 years ago

I've checked the Travis CI build error, seems related to log file length, I cannot see the error. Do you confirm?

@dloic hmm apparently Travis enforces a 4MB log length limit, it's the first time I've seen this issue though. Try to add the - quiet option at the end of the three xcodebuild commands in the travis config file, that should shrink the log output sufficiently.

dloic commented 3 years ago

@johnxnguyen Thanks for the review. Branch updated taking into account all your feedback. I did also tweak the travis script as suggested. Let see the result!

Updated usage of the new feature with builder as closure:

let visitor = AttributedStringVisitor(
    styler: DownStyler(),
    options: .default,
    listPrefixGeneratorBuilder: { CustomListItemPrefixGenerator(list: $0) }
)
dloic commented 3 years ago

Thanks to you @johnxnguyen for the review and approval! There is no rush, but I was wondering if you plan to do a new release for the new changes.

johnxnguyen commented 3 years ago

I will draft a new release likely by the end of this week.

dloic commented 3 years ago

Perfect, thanks a lot!

johnxnguyen commented 3 years ago

FYI @dloic this has been release. Thanks again for the contribution!