33
33
/// override how individual Markdown structures are converted into attributed strings.
34
34
///
35
35
open class AttributedStringGenerator {
36
-
36
+
37
+ /// Options for the attributed string generator
38
+ public struct Options : OptionSet {
39
+ public let rawValue : UInt
40
+
41
+ public init ( rawValue: UInt ) {
42
+ self . rawValue = rawValue
43
+ }
44
+
45
+ public static let tightLists = Options ( rawValue: 1 << 0 )
46
+ }
47
+
37
48
/// Customized html generator to work around limitations of the current HTML to
38
49
/// `NSAttributedString` conversion logic provided by the operating system.
39
50
open class InternalHtmlGenerator : HtmlGenerator {
40
- var outer : AttributedStringGenerator ?
51
+ var outer : AttributedStringGenerator
41
52
42
53
public init ( outer: AttributedStringGenerator ) {
43
54
self . outer = outer
44
55
}
45
56
46
- open override func generate( block: Block , tight: Bool = false ) -> String {
57
+ open override func generate( block: Block , parent : Parent , tight: Bool = false ) -> String {
47
58
switch block {
48
59
case . list( _, _, _) :
49
- return super. generate ( block: block, tight: tight) + " <p style= \" margin: 0; \" /> \n "
60
+ let res = super. generate ( block: block, parent: . block( block, parent) , tight: tight)
61
+ if case . block( . listItem( _, _, _) , _) = parent {
62
+ return res
63
+ } else {
64
+ return res + " <p style= \" margin: 0; \" /> \n "
65
+ }
66
+ case . paragraph( let text) :
67
+ if case . block( . listItem( _, _, _) , . block( . list( _, let tight, _) , _) ) = parent,
68
+ tight || self . outer. options. contains ( . tightLists) {
69
+ return self . generate ( text: text) + " \n "
70
+ } else {
71
+ return " <p> " + self . generate ( text: text) + " </p> \n "
72
+ }
50
73
case . indentedCode( _) ,
51
74
. fencedCode( _, _) :
52
75
return " <table style= \" width: 100%; margin-bottom: 3px; \" ><tbody><tr> " +
53
76
" <td class= \" codebox \" > " +
54
- super. generate ( block: block, tight: tight) +
77
+ super. generate ( block: block, parent : . block ( block , parent ) , tight: tight) +
55
78
" </td></tr></tbody></table><p style= \" margin: 0; \" /> \n "
56
79
case . blockquote( let blocks) :
57
80
return " <table class= \" blockquote \" ><tbody><tr> " +
58
81
" <td class= \" quote \" /><td style= \" width: 0.5em; \" /><td> \n " +
59
- self . generate ( blocks: blocks) +
82
+ self . generate ( blocks: blocks, parent : . block ( block , parent ) ) +
60
83
" </td></tr><tr style= \" height: 0; \" ><td /><td /><td /></tr></tbody></table> \n "
61
84
case . thematicBreak:
62
85
return " <p><table style= \" width: 100%; margin-bottom: 3px; \" ><tbody> " +
@@ -76,7 +99,7 @@ open class AttributedStringGenerator {
76
99
}
77
100
}
78
101
var html = " <table class= \" mtable \" " +
79
- " cellpadding= \" \( self . outer? . tableCellPadding ?? 2 ) \" ><thead><tr> \n "
102
+ " cellpadding= \" \( self . outer. tableCellPadding) \" ><thead><tr> \n "
80
103
var i = 0
81
104
for head in header {
82
105
html += " <th \( tagsuffix [ i] ) \( self . generate ( text: head) ) </th> "
@@ -100,7 +123,9 @@ open class AttributedStringGenerator {
100
123
html += " <dt> " + self . generate ( text: def. item) + " </dt> \n "
101
124
for descr in def. descriptions {
102
125
if case . listItem( _, _, let blocks) = descr {
103
- html += " <dd> " + self . generate ( blocks: blocks) + " </dd> \n "
126
+ html += " <dd> " +
127
+ self . generate ( blocks: blocks, parent: . block( block, parent) ) +
128
+ " </dd> \n "
104
129
}
105
130
}
106
131
}
@@ -109,7 +134,7 @@ open class AttributedStringGenerator {
109
134
case . custom( let customBlock) :
110
135
return customBlock. generateHtml ( via: self , and: self . outer, tight: tight)
111
136
default :
112
- return super. generate ( block: block, tight: tight)
137
+ return super. generate ( block: block, parent : parent , tight: tight)
113
138
}
114
139
}
115
140
@@ -120,7 +145,7 @@ open class AttributedStringGenerator {
120
145
if let uriStr = uri {
121
146
let url = URL ( string: uriStr)
122
147
if ( url? . scheme == nil ) || ( url? . isFileURL ?? false ) ,
123
- let baseUrl = self . outer? . imageBaseUrl {
148
+ let baseUrl = self . outer. imageBaseUrl {
124
149
let url = URL ( fileURLWithPath: uriStr, relativeTo: baseUrl)
125
150
if url. isFileURL {
126
151
return " <img src= \" \( url. absoluteString) \" " +
@@ -142,6 +167,9 @@ open class AttributedStringGenerator {
142
167
/// Default `AttributedStringGenerator` implementation.
143
168
public static let standard : AttributedStringGenerator = AttributedStringGenerator ( )
144
169
170
+ /// The generator options.
171
+ public let options : Options
172
+
145
173
/// The base font size.
146
174
public let fontSize : Float
147
175
@@ -201,7 +229,8 @@ open class AttributedStringGenerator {
201
229
202
230
203
231
/// Constructor providing customization options for the generated `NSAttributedString` markup.
204
- public init ( fontSize: Float = 14.0 ,
232
+ public init ( options: Options = [ ] ,
233
+ fontSize: Float = 14.0 ,
205
234
fontFamily: String = " \" Times New Roman \" ,Times,serif " ,
206
235
fontColor: String = mdDefaultColor,
207
236
codeFontSize: Float = 13.0 ,
@@ -221,6 +250,7 @@ open class AttributedStringGenerator {
221
250
maxImageHeight: String ? = nil ,
222
251
customStyle: String = " " ,
223
252
imageBaseUrl: URL ? = nil ) {
253
+ self . options = options
224
254
self . fontSize = fontSize
225
255
self . fontFamily = fontFamily
226
256
self . fontColor = fontColor
@@ -249,21 +279,23 @@ open class AttributedStringGenerator {
249
279
250
280
/// Generates an attributed string from the given Markdown blocks
251
281
open func generate( block: Block ) -> NSAttributedString ? {
252
- return self . generateAttributedString ( self . htmlGenerator. generate ( block: block) )
282
+ return self . generateAttributedString ( self . htmlGenerator. generate ( block: block, parent : . none ) )
253
283
}
254
284
255
285
/// Generates an attributed string from the given Markdown blocks
256
286
open func generate( blocks: Blocks ) -> NSAttributedString ? {
257
- return self . generateAttributedString ( self . htmlGenerator. generate ( blocks: blocks) )
287
+ return self . generateAttributedString ( self . htmlGenerator. generate ( blocks: blocks, parent : . none ) )
258
288
}
259
289
260
290
private func generateAttributedString( _ htmlBody: String ) -> NSAttributedString ? {
261
- let htmlDoc = self . generateHtml ( htmlBody)
262
- let httpData = Data ( htmlDoc. utf8)
263
- return try ? NSAttributedString ( data: httpData,
264
- options: [ . documentType: NSAttributedString . DocumentType. html,
265
- . characterEncoding: String . Encoding. utf8. rawValue] ,
266
- documentAttributes: nil )
291
+ if let httpData = self . generateHtml ( htmlBody) . data ( using: . utf8) {
292
+ return try ? NSAttributedString ( data: httpData,
293
+ options: [ . documentType: NSAttributedString . DocumentType. html,
294
+ . characterEncoding: String . Encoding. utf8. rawValue] ,
295
+ documentAttributes: nil )
296
+ } else {
297
+ return nil
298
+ }
267
299
}
268
300
269
301
open var htmlGenerator : HtmlGenerator {
0 commit comments