Skip to content

Commit

Permalink
fix newline & ordered list rendering issues
Browse files Browse the repository at this point in the history
  • Loading branch information
LiYanan2004 committed Feb 13, 2025
1 parent 6065873 commit a7d2672
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 64 deletions.
55 changes: 40 additions & 15 deletions Sources/MarkdownView/Configuration/Markdown.ListConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,46 @@ struct MarkdownListConfiguration: Hashable, @unchecked Sendable {

public protocol OrderedListMarkerProtocol: Hashable {
/// Returns a marker for a specific index of ordered list item. Index starting from 0.
func marker(at index: Int) -> String
func marker(at index: Int, listDepth: Int) -> String

var monospaced: Bool { get }
}

extension OrderedListMarkerProtocol {
public var monospaced: Bool {
true
}
}

struct AnyOrderedListMarkerProtocol: OrderedListMarkerProtocol {
private var _marker: AnyHashable
var monospaced: Bool {
(_marker as! (any OrderedListMarkerProtocol)).monospaced
}

init(_ marker: some OrderedListMarkerProtocol) {
init<T: OrderedListMarkerProtocol>(_ marker: T) {
self._marker = AnyHashable(marker)
}

public func marker(at index: Int) -> String {
(_marker as! (any OrderedListMarkerProtocol)).marker(at: index)
public func marker(at index: Int, listDepth: Int) -> String {
(_marker as! (any OrderedListMarkerProtocol)).marker(at: index, listDepth: listDepth)
}
}


public struct OrderedListIncreasingDigitsMarker: OrderedListMarkerProtocol {
public func marker(at index: Int) -> String {
String(index + 1)
public func marker(at index: Int, listDepth: Int) -> String {
String(index + 1) + "."
}

public var monospaced: Bool { false }
}

extension OrderedListMarkerProtocol where Self == OrderedListIncreasingDigitsMarker {
static public var increasingDigits: OrderedListIncreasingDigitsMarker { .init() }
}

public struct OrderedListIncreasingLettersMarker: OrderedListMarkerProtocol {
public func marker(at index: Int) -> String {
public func marker(at index: Int, listDepth: Int) -> String {
let base = 26
var index = index
var result = ""
Expand All @@ -63,8 +75,10 @@ public struct OrderedListIncreasingLettersMarker: OrderedListMarkerProtocol {
result.append(Character(secondLetter))
}

return result
return result + "."
}

public var monospaced: Bool { false }
}

extension OrderedListMarkerProtocol where Self == OrderedListIncreasingLettersMarker {
Expand All @@ -75,23 +89,34 @@ extension OrderedListMarkerProtocol where Self == OrderedListIncreasingLettersMa

public protocol UnorderedListMarkerProtocol: Hashable {
/// Returns a marker for a specific indentation level of unordered list item. indentationLevel starting from 0.
func marker(at indentationLevel: Int) -> String
func marker(listDepth: Int) -> String

var monospaced: Bool { get }
}

extension UnorderedListMarkerProtocol {
public var monospaced: Bool {
true
}
}

struct AnyUnorderedListMarkerProtocol: UnorderedListMarkerProtocol {
private var _marker: AnyHashable
var monospaced: Bool {
(_marker as! (any UnorderedListMarkerProtocol)).monospaced
}

init(_ marker: some UnorderedListMarkerProtocol) {
init<T: UnorderedListMarkerProtocol>(_ marker: T) {
self._marker = AnyHashable(marker)
}

public func marker(at indentationLevel: Int) -> String {
(_marker as! (any UnorderedListMarkerProtocol)).marker(at: indentationLevel)
public func marker(listDepth: Int) -> String {
(_marker as! (any UnorderedListMarkerProtocol)).marker(listDepth: listDepth)
}
}

public struct UnorderedListDashMarker: UnorderedListMarkerProtocol {
public func marker(at indentationLevel: Int) -> String {
public func marker(listDepth: Int) -> String {
"-"
}
}
Expand All @@ -101,7 +126,7 @@ extension UnorderedListMarkerProtocol where Self == UnorderedListDashMarker {
}

public struct UnorderedListBulletMarker: UnorderedListMarkerProtocol {
public func marker(at indentationLevel: Int) -> String {
public func marker(listDepth: Int) -> String {
""
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ extension MarkdownViewRenderer {
if listItem.checkbox != nil {
CheckboxView(listItem: listItem)
} else {
SwiftUI.Text(configuration.listConfiguration.unorderedListMarker.marker(at: unorderedList.listDepth))
SwiftUI.Text(configuration.listConfiguration.unorderedListMarker.marker(listDepth: unorderedList.listDepth))
.font(.title2)
.padding(.leading, depth == 0 ? configuration.listConfiguration.leadingIndent : 0)
}
Expand Down
18 changes: 2 additions & 16 deletions Sources/MarkdownView/WIP/MarkdownText/MarkdownTextNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,20 +103,6 @@ enum MarkdownTextKind: Sendable, Equatable {

case placeholder(UUID) // A placeholder to enable async resources loading, e.g. image loading
case image(Image)
}


fileprivate extension Font {
static func heading(level: Int) -> Font {
@Environment(\.markdownRendererConfiguration.fontGroup) var fontGroup
return switch level {
case 1: fontGroup.h1
case 2: fontGroup.h2
case 3: fontGroup.h3
case 4: fontGroup.h4
case 5: fontGroup.h5
case 6: fontGroup.h6
default: fontGroup.body
}
}

case unknown
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ struct MarkdownTextRenderer: MarkupVisitor {
}

mutating func defaultVisit(_ markup: any Markdown.Markup) -> MarkdownTextNode {
MarkdownTextNode(kind: .placeholder(UUID()), children: [])
MarkdownTextNode(
kind: .unknown,
children: markup.children.enumerated().map {
visit($0.element)
.with(\.index, $0.offset)
}
)
}

mutating func visitDocument(_ document: Document) -> MarkdownTextNode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import Highlightr

struct CodeBlockTextRenderer: MarkdownNode2TextRenderer {
func body(context: Context) -> Text {
BreakTextRenderer(breakType: .hard)
.body(context: context)
BreakTextRenderer(breakType: .hard)
.body(context: context)
if context.node.index != 0 {
BreakTextRenderer(breakType: .hard)
.body(context: context)
}

let language = if case let .codeLanguage(language) = context.node.content! {
language
Expand Down Expand Up @@ -47,9 +47,6 @@ struct CodeBlockTextRenderer: MarkdownNode2TextRenderer {
Text(processedCode)
.font(.callout.monospaced())
}

BreakTextRenderer(breakType: .hard)
.body(context: context)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ import SwiftUI

struct HeadingTextRenderer: MarkdownNode2TextRenderer {
func body(context: Context) -> Text {
BreakTextRenderer(breakType: .hard)
.body(context: context)

let level = if case let .heading(level) = context.node.content {
level
} else {
Expand Down Expand Up @@ -50,5 +47,8 @@ struct HeadingTextRenderer: MarkdownNode2TextRenderer {
.reduce(Text(""), +)
.font(font)
}

BreakTextRenderer(breakType: .hard)
.body(context: context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import SwiftUI
struct InlineCodeTextRenderer: MarkdownNode2TextRenderer {
func body(context: Context) -> Text {
if case let .text(text) = context.node.content! {
Text(text).font(.body.monospaced())
if #available(iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4, *) {
Text(text).monospaced()
} else {
Text(text).font(.body.monospaced())
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,36 @@ import SwiftUI

struct OrderedListTextRenderer: MarkdownNode2TextRenderer {
func body(context: Context) -> Text {
BreakTextRenderer(breakType: .hard)
.body(context: context)

let listConfiguration = context.renderConfiguration.listConfiguration
let marker = Text("\(listConfiguration.orderedListMarker.marker(at: context.node.depth ?? 0)) ")
.font(.body.monospaced())
let indents = context.node.depth ?? 0
let indentation = (0..<indents).reduce(Text("")) { indent, _ in
indent + Text("\t")
}

context.node.children
.map { $0.render(configuration: context.renderConfiguration) }
.reduce(Text("")) { list, item in
list + marker + item
.enumerated()
.reduce(Text("")) { list, enumeratedItem in
let (offset, listItem) = enumeratedItem
let marker = markerText(context: context, index: offset)
return list + indentation + marker + listItem
}
}

@TextBuilder
private func markerText(context: Context, index: Int) -> Text {
let marker = context.renderConfiguration.listConfiguration
.orderedListMarker
.marker(at: index, listDepth: context.node.depth ?? 0)
if context.renderConfiguration.listConfiguration.orderedListMarker.monospaced {
if #available(iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4, *) {
Text("\(marker) ")
.monospaced()
} else {
Text("\(marker) ")
.font(.body.monospaced())
}
} else {
Text("\(marker) ")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import SwiftUI

struct ParagraphTextRenderer: MarkdownNode2TextRenderer {
func body(context: Context) -> Text {
if context.node.index != 0 {
BreakTextRenderer(breakType: .hard)
.body(context: context)
}
context.node.children
.map { $0.render(configuration: context.renderConfiguration) }
.reduce(Text(""), +)
BreakTextRenderer(breakType: .hard)
.body(context: context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,34 @@ import SwiftUI

struct UnorderedListTextRenderer: MarkdownNode2TextRenderer {
func body(context: Context) -> Text {
let listConfiguration = context.renderConfiguration.listConfiguration
let marker = Text("\(listConfiguration.unorderedListMarker.marker(at: context.node.depth ?? 0)) ")
.font(.body.monospaced())

let lineBreak = BreakTextRenderer(breakType: .hard)
.body(context: context)
let indents = context.node.depth ?? 0
let indentation = (0..<indents).reduce(Text("")) { indent, _ in
indent + Text("\t")
}

context.node.children
.map { $0.render(configuration: context.renderConfiguration) }
.reduce(Text("")) { list, item in
list + lineBreak + indentation + marker + item
.reduce(Text("")) { list, listItem in
let marker = markerText(context: context)
return list + indentation + marker + listItem
}
}

@TextBuilder
private func markerText(context: Context) -> Text {
let marker = context.renderConfiguration.listConfiguration
.unorderedListMarker
.marker(listDepth: context.node.depth ?? 0)
if context.renderConfiguration.listConfiguration.unorderedListMarker.monospaced {
if #available(iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4, *) {
Text("\(marker) ")
.monospaced()
} else {
Text("\(marker) ")
.font(.body.monospaced())
}
} else {
Text("\(marker) ")
}
}
}

0 comments on commit a7d2672

Please sign in to comment.