3333/// override how individual Markdown structures are converted into attributed strings.
3434///
3535open 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+
3748 /// Customized html generator to work around limitations of the current HTML to
3849 /// `NSAttributedString` conversion logic provided by the operating system.
3950 open class InternalHtmlGenerator : HtmlGenerator {
40- var outer : AttributedStringGenerator ?
51+ var outer : AttributedStringGenerator
4152
4253 public init ( outer: AttributedStringGenerator ) {
4354 self . outer = outer
4455 }
4556
46- open override func generate( block: Block , tight: Bool = false ) -> String {
57+ open override func generate( block: Block , parent : Parent , tight: Bool = false ) -> String {
4758 switch block {
4859 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+ }
5073 case . indentedCode( _) ,
5174 . fencedCode( _, _) :
5275 return " <table style= \" width: 100%; margin-bottom: 3px; \" ><tbody><tr> " +
5376 " <td class= \" codebox \" > " +
54- super. generate ( block: block, tight: tight) +
77+ super. generate ( block: block, parent : . block ( block , parent ) , tight: tight) +
5578 " </td></tr></tbody></table><p style= \" margin: 0; \" /> \n "
5679 case . blockquote( let blocks) :
5780 return " <table class= \" blockquote \" ><tbody><tr> " +
5881 " <td class= \" quote \" /><td style= \" width: 0.5em; \" /><td> \n " +
59- self . generate ( blocks: blocks) +
82+ self . generate ( blocks: blocks, parent : . block ( block , parent ) ) +
6083 " </td></tr><tr style= \" height: 0; \" ><td /><td /><td /></tr></tbody></table> \n "
6184 case . thematicBreak:
6285 return " <p><table style= \" width: 100%; margin-bottom: 3px; \" ><tbody> " +
@@ -76,7 +99,7 @@ open class AttributedStringGenerator {
7699 }
77100 }
78101 var html = " <table class= \" mtable \" " +
79- " cellpadding= \" \( self . outer? . tableCellPadding ?? 2 ) \" ><thead><tr> \n "
102+ " cellpadding= \" \( self . outer. tableCellPadding) \" ><thead><tr> \n "
80103 var i = 0
81104 for head in header {
82105 html += " <th \( tagsuffix [ i] ) \( self . generate ( text: head) ) </th> "
@@ -100,7 +123,9 @@ open class AttributedStringGenerator {
100123 html += " <dt> " + self . generate ( text: def. item) + " </dt> \n "
101124 for descr in def. descriptions {
102125 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 "
104129 }
105130 }
106131 }
@@ -109,7 +134,7 @@ open class AttributedStringGenerator {
109134 case . custom( let customBlock) :
110135 return customBlock. generateHtml ( via: self , and: self . outer, tight: tight)
111136 default :
112- return super. generate ( block: block, tight: tight)
137+ return super. generate ( block: block, parent : parent , tight: tight)
113138 }
114139 }
115140
@@ -120,7 +145,7 @@ open class AttributedStringGenerator {
120145 if let uriStr = uri {
121146 let url = URL ( string: uriStr)
122147 if ( url? . scheme == nil ) || ( url? . isFileURL ?? false ) ,
123- let baseUrl = self . outer? . imageBaseUrl {
148+ let baseUrl = self . outer. imageBaseUrl {
124149 let url = URL ( fileURLWithPath: uriStr, relativeTo: baseUrl)
125150 if url. isFileURL {
126151 return " <img src= \" \( url. absoluteString) \" " +
@@ -142,6 +167,9 @@ open class AttributedStringGenerator {
142167 /// Default `AttributedStringGenerator` implementation.
143168 public static let standard : AttributedStringGenerator = AttributedStringGenerator ( )
144169
170+ /// The generator options.
171+ public let options : Options
172+
145173 /// The base font size.
146174 public let fontSize : Float
147175
@@ -201,7 +229,8 @@ open class AttributedStringGenerator {
201229
202230
203231 /// 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 ,
205234 fontFamily: String = " \" Times New Roman \" ,Times,serif " ,
206235 fontColor: String = mdDefaultColor,
207236 codeFontSize: Float = 13.0 ,
@@ -221,6 +250,7 @@ open class AttributedStringGenerator {
221250 maxImageHeight: String ? = nil ,
222251 customStyle: String = " " ,
223252 imageBaseUrl: URL ? = nil ) {
253+ self . options = options
224254 self . fontSize = fontSize
225255 self . fontFamily = fontFamily
226256 self . fontColor = fontColor
@@ -249,21 +279,23 @@ open class AttributedStringGenerator {
249279
250280 /// Generates an attributed string from the given Markdown blocks
251281 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 ) )
253283 }
254284
255285 /// Generates an attributed string from the given Markdown blocks
256286 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 ) )
258288 }
259289
260290 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+ }
267299 }
268300
269301 open var htmlGenerator : HtmlGenerator {
0 commit comments