@@ -42,7 +42,7 @@ func isdigit(c byte) bool {
4242 return c >= '0' && c <= '9'
4343}
4444
45- func smartQuoteHelper (out * bytes.Buffer , previousChar byte , nextChar byte , quote byte , isOpen * bool ) bool {
45+ func smartQuoteHelper (out * bytes.Buffer , previousChar byte , nextChar byte , quote byte , isOpen * bool , addNBSP bool ) bool {
4646 // edge of the buffer is likely to be a tag that we don't get to see,
4747 // so we treat it like text sometimes
4848
@@ -99,6 +99,12 @@ func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote
9999 * isOpen = false
100100 }
101101
102+ // Note that with the limited lookahead, this non-breaking
103+ // space will also be appended to single double quotes.
104+ if addNBSP && ! * isOpen {
105+ out .WriteString (" " )
106+ }
107+
102108 out .WriteByte ('&' )
103109 if * isOpen {
104110 out .WriteByte ('l' )
@@ -107,6 +113,11 @@ func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote
107113 }
108114 out .WriteByte (quote )
109115 out .WriteString ("quo;" )
116+
117+ if addNBSP && * isOpen {
118+ out .WriteString (" " )
119+ }
120+
110121 return true
111122}
112123
@@ -119,7 +130,7 @@ func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text
119130 if len (text ) >= 3 {
120131 nextChar = text [2 ]
121132 }
122- if smartQuoteHelper (out , previousChar , nextChar , 'd' , & r .inDoubleQuote ) {
133+ if smartQuoteHelper (out , previousChar , nextChar , 'd' , & r .inDoubleQuote , false ) {
123134 return 1
124135 }
125136 }
@@ -144,7 +155,7 @@ func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text
144155 if len (text ) > 1 {
145156 nextChar = text [1 ]
146157 }
147- if smartQuoteHelper (out , previousChar , nextChar , 's' , & r .inSingleQuote ) {
158+ if smartQuoteHelper (out , previousChar , nextChar , 's' , & r .inSingleQuote , false ) {
148159 return 0
149160 }
150161
@@ -208,13 +219,13 @@ func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text [
208219 return 0
209220}
210221
211- func (r * SPRenderer ) smartAmpVariant (out * bytes.Buffer , previousChar byte , text []byte , quote byte ) int {
222+ func (r * SPRenderer ) smartAmpVariant (out * bytes.Buffer , previousChar byte , text []byte , quote byte , addNBSP bool ) int {
212223 if bytes .HasPrefix (text , []byte (""" )) {
213224 nextChar := byte (0 )
214225 if len (text ) >= 7 {
215226 nextChar = text [6 ]
216227 }
217- if smartQuoteHelper (out , previousChar , nextChar , quote , & r .inDoubleQuote ) {
228+ if smartQuoteHelper (out , previousChar , nextChar , quote , & r .inDoubleQuote , addNBSP ) {
218229 return 5
219230 }
220231 }
@@ -227,12 +238,15 @@ func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text
227238 return 0
228239}
229240
230- func (r * SPRenderer ) smartAmp (out * bytes.Buffer , previousChar byte , text []byte ) int {
231- return r .smartAmpVariant (out , previousChar , text , 'd' )
232- }
241+ func (r * SPRenderer ) smartAmp (angledQuotes , addNBSP bool ) func (* bytes.Buffer , byte , []byte ) int {
242+ var quote byte = 'd'
243+ if angledQuotes {
244+ quote = 'a'
245+ }
233246
234- func (r * SPRenderer ) smartAmpAngledQuote (out * bytes.Buffer , previousChar byte , text []byte ) int {
235- return r .smartAmpVariant (out , previousChar , text , 'a' )
247+ return func (out * bytes.Buffer , previousChar byte , text []byte ) int {
248+ return r .smartAmpVariant (out , previousChar , text , quote , addNBSP )
249+ }
236250}
237251
238252func (r * SPRenderer ) smartPeriod (out * bytes.Buffer , previousChar byte , text []byte ) int {
@@ -256,7 +270,7 @@ func (r *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []
256270 if len (text ) >= 3 {
257271 nextChar = text [2 ]
258272 }
259- if smartQuoteHelper (out , previousChar , nextChar , 'd' , & r .inDoubleQuote ) {
273+ if smartQuoteHelper (out , previousChar , nextChar , 'd' , & r .inDoubleQuote , false ) {
260274 return 1
261275 }
262276 }
@@ -340,7 +354,7 @@ func (r *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byt
340354 if len (text ) > 1 {
341355 nextChar = text [1 ]
342356 }
343- if ! smartQuoteHelper (out , previousChar , nextChar , quote , & r .inDoubleQuote ) {
357+ if ! smartQuoteHelper (out , previousChar , nextChar , quote , & r .inDoubleQuote , false ) {
344358 out .WriteString (""" )
345359 }
346360
@@ -370,13 +384,31 @@ type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int
370384
371385// NewSmartypantsRenderer constructs a Smartypants renderer object.
372386func NewSmartypantsRenderer (flags HTMLFlags ) * SPRenderer {
373- var r SPRenderer
387+ var (
388+ r SPRenderer
389+
390+ smartAmpAngled = r .smartAmp (true , false )
391+ smartAmpAngledNBSP = r .smartAmp (true , true )
392+ smartAmpRegular = r .smartAmp (false , false )
393+ smartAmpRegularNBSP = r .smartAmp (false , true )
394+
395+ addNBSP = flags & SmartypantsQuotesNBSP != 0
396+ )
397+
374398 if flags & SmartypantsAngledQuotes == 0 {
375399 r .callbacks ['"' ] = r .smartDoubleQuote
376- r .callbacks ['&' ] = r .smartAmp
400+ if ! addNBSP {
401+ r .callbacks ['&' ] = smartAmpRegular
402+ } else {
403+ r .callbacks ['&' ] = smartAmpRegularNBSP
404+ }
377405 } else {
378406 r .callbacks ['"' ] = r .smartAngledDoubleQuote
379- r .callbacks ['&' ] = r .smartAmpAngledQuote
407+ if ! addNBSP {
408+ r .callbacks ['&' ] = smartAmpAngled
409+ } else {
410+ r .callbacks ['&' ] = smartAmpAngledNBSP
411+ }
380412 }
381413 r .callbacks ['\'' ] = r .smartSingleQuote
382414 r .callbacks ['(' ] = r .smartParens
0 commit comments