mirror of
https://github.com/danog/blackfriday.git
synced 2024-11-30 04:29:13 +01:00
Add Smartypants support for French Guillemets
This is a port of the fix for #378 in v1. Fixes #380
This commit is contained in:
parent
f42ca5bf18
commit
3a1d515242
1
html.go
1
html.go
@ -44,6 +44,7 @@ const (
|
|||||||
SmartypantsDashes // Enable smart dashes (with Smartypants)
|
SmartypantsDashes // Enable smart dashes (with Smartypants)
|
||||||
SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants)
|
SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants)
|
||||||
SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering
|
SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering
|
||||||
|
SmartypantsQuotesNBSP // Enable « French guillemets » (with Smartypants)
|
||||||
TOC // Generate a table of contents
|
TOC // Generate a table of contents
|
||||||
|
|
||||||
TagName = "[A-Za-z][A-Za-z0-9-]*"
|
TagName = "[A-Za-z][A-Za-z0-9-]*"
|
||||||
|
@ -1034,6 +1034,18 @@ func TestSmartDoubleQuotes(t *testing.T) {
|
|||||||
doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants})
|
doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSmartDoubleQuotesNBSP(t *testing.T) {
|
||||||
|
var tests = []string{
|
||||||
|
"this should be normal \"quoted\" text.\n",
|
||||||
|
"<p>this should be normal “ quoted ” text.</p>\n",
|
||||||
|
"this \" single double\n",
|
||||||
|
"<p>this “ single double</p>\n",
|
||||||
|
"two pair of \"some\" quoted \"text\".\n",
|
||||||
|
"<p>two pair of “ some ” quoted “ text ”.</p>\n"}
|
||||||
|
|
||||||
|
doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants | SmartypantsQuotesNBSP})
|
||||||
|
}
|
||||||
|
|
||||||
func TestSmartAngledDoubleQuotes(t *testing.T) {
|
func TestSmartAngledDoubleQuotes(t *testing.T) {
|
||||||
var tests = []string{
|
var tests = []string{
|
||||||
"this should be angled \"quoted\" text.\n",
|
"this should be angled \"quoted\" text.\n",
|
||||||
@ -1046,6 +1058,18 @@ func TestSmartAngledDoubleQuotes(t *testing.T) {
|
|||||||
doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants | SmartypantsAngledQuotes})
|
doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants | SmartypantsAngledQuotes})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSmartAngledDoubleQuotesNBSP(t *testing.T) {
|
||||||
|
var tests = []string{
|
||||||
|
"this should be angled \"quoted\" text.\n",
|
||||||
|
"<p>this should be angled « quoted » text.</p>\n",
|
||||||
|
"this \" single double\n",
|
||||||
|
"<p>this « single double</p>\n",
|
||||||
|
"two pair of \"some\" quoted \"text\".\n",
|
||||||
|
"<p>two pair of « some » quoted « text ».</p>\n"}
|
||||||
|
|
||||||
|
doTestsInlineParam(t, tests, TestParams{HTMLFlags: Smartypants | SmartypantsAngledQuotes | SmartypantsQuotesNBSP})
|
||||||
|
}
|
||||||
|
|
||||||
func TestSmartFractions(t *testing.T) {
|
func TestSmartFractions(t *testing.T) {
|
||||||
var tests = []string{
|
var tests = []string{
|
||||||
"1/2, 1/4 and 3/4; 1/4th and 3/4ths\n",
|
"1/2, 1/4 and 3/4; 1/4th and 3/4ths\n",
|
||||||
@ -1140,3 +1164,13 @@ func TestSkipHTML(t *testing.T) {
|
|||||||
"<p>text inline html more text</p>\n",
|
"<p>text inline html more text</p>\n",
|
||||||
}, TestParams{HTMLFlags: SkipHTML})
|
}, TestParams{HTMLFlags: SkipHTML})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkSmartDoubleQuotes(b *testing.B) {
|
||||||
|
params := TestParams{HTMLFlags: Smartypants}
|
||||||
|
params.extensions |= Autolink | Strikethrough
|
||||||
|
params.HTMLFlags |= UseXHTML
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
runMarkdown("this should be normal \"quoted\" text.\n", params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -42,7 +42,7 @@ func isdigit(c byte) bool {
|
|||||||
return c >= '0' && c <= '9'
|
return c >= '0' && c <= '9'
|
||||||
}
|
}
|
||||||
|
|
||||||
func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool) bool {
|
func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool, addNBSP bool) bool {
|
||||||
// edge of the buffer is likely to be a tag that we don't get to see,
|
// edge of the buffer is likely to be a tag that we don't get to see,
|
||||||
// so we treat it like text sometimes
|
// so we treat it like text sometimes
|
||||||
|
|
||||||
@ -99,6 +99,12 @@ func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote
|
|||||||
*isOpen = false
|
*isOpen = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note that with the limited lookahead, this non-breaking
|
||||||
|
// space will also be appended to single double quotes.
|
||||||
|
if addNBSP && !*isOpen {
|
||||||
|
out.WriteString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
out.WriteByte('&')
|
out.WriteByte('&')
|
||||||
if *isOpen {
|
if *isOpen {
|
||||||
out.WriteByte('l')
|
out.WriteByte('l')
|
||||||
@ -107,6 +113,11 @@ func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote
|
|||||||
}
|
}
|
||||||
out.WriteByte(quote)
|
out.WriteByte(quote)
|
||||||
out.WriteString("quo;")
|
out.WriteString("quo;")
|
||||||
|
|
||||||
|
if addNBSP && *isOpen {
|
||||||
|
out.WriteString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +130,7 @@ func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text
|
|||||||
if len(text) >= 3 {
|
if len(text) >= 3 {
|
||||||
nextChar = text[2]
|
nextChar = text[2]
|
||||||
}
|
}
|
||||||
if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote) {
|
if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,7 +155,7 @@ func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text
|
|||||||
if len(text) > 1 {
|
if len(text) > 1 {
|
||||||
nextChar = text[1]
|
nextChar = text[1]
|
||||||
}
|
}
|
||||||
if smartQuoteHelper(out, previousChar, nextChar, 's', &r.inSingleQuote) {
|
if smartQuoteHelper(out, previousChar, nextChar, 's', &r.inSingleQuote, false) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,13 +219,13 @@ func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text [
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int {
|
func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte, addNBSP bool) int {
|
||||||
if bytes.HasPrefix(text, []byte(""")) {
|
if bytes.HasPrefix(text, []byte(""")) {
|
||||||
nextChar := byte(0)
|
nextChar := byte(0)
|
||||||
if len(text) >= 7 {
|
if len(text) >= 7 {
|
||||||
nextChar = text[6]
|
nextChar = text[6]
|
||||||
}
|
}
|
||||||
if smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote) {
|
if smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, addNBSP) {
|
||||||
return 5
|
return 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,12 +238,15 @@ func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SPRenderer) smartAmp(out *bytes.Buffer, previousChar byte, text []byte) int {
|
func (r *SPRenderer) smartAmp(angledQuotes, addNBSP bool) func(*bytes.Buffer, byte, []byte) int {
|
||||||
return r.smartAmpVariant(out, previousChar, text, 'd')
|
var quote byte = 'd'
|
||||||
}
|
if angledQuotes {
|
||||||
|
quote = 'a'
|
||||||
|
}
|
||||||
|
|
||||||
func (r *SPRenderer) smartAmpAngledQuote(out *bytes.Buffer, previousChar byte, text []byte) int {
|
return func(out *bytes.Buffer, previousChar byte, text []byte) int {
|
||||||
return r.smartAmpVariant(out, previousChar, text, 'a')
|
return r.smartAmpVariant(out, previousChar, text, quote, addNBSP)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []byte) int {
|
func (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 []
|
|||||||
if len(text) >= 3 {
|
if len(text) >= 3 {
|
||||||
nextChar = text[2]
|
nextChar = text[2]
|
||||||
}
|
}
|
||||||
if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote) {
|
if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -340,7 +354,7 @@ func (r *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byt
|
|||||||
if len(text) > 1 {
|
if len(text) > 1 {
|
||||||
nextChar = text[1]
|
nextChar = text[1]
|
||||||
}
|
}
|
||||||
if !smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote) {
|
if !smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, false) {
|
||||||
out.WriteString(""")
|
out.WriteString(""")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,13 +384,31 @@ type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int
|
|||||||
|
|
||||||
// NewSmartypantsRenderer constructs a Smartypants renderer object.
|
// NewSmartypantsRenderer constructs a Smartypants renderer object.
|
||||||
func NewSmartypantsRenderer(flags HTMLFlags) *SPRenderer {
|
func NewSmartypantsRenderer(flags HTMLFlags) *SPRenderer {
|
||||||
var r SPRenderer
|
var (
|
||||||
|
r SPRenderer
|
||||||
|
|
||||||
|
smartAmpAngled = r.smartAmp(true, false)
|
||||||
|
smartAmpAngledNBSP = r.smartAmp(true, true)
|
||||||
|
smartAmpRegular = r.smartAmp(false, false)
|
||||||
|
smartAmpRegularNBSP = r.smartAmp(false, true)
|
||||||
|
|
||||||
|
addNBSP = flags&SmartypantsQuotesNBSP != 0
|
||||||
|
)
|
||||||
|
|
||||||
if flags&SmartypantsAngledQuotes == 0 {
|
if flags&SmartypantsAngledQuotes == 0 {
|
||||||
r.callbacks['"'] = r.smartDoubleQuote
|
r.callbacks['"'] = r.smartDoubleQuote
|
||||||
r.callbacks['&'] = r.smartAmp
|
if !addNBSP {
|
||||||
|
r.callbacks['&'] = smartAmpRegular
|
||||||
|
} else {
|
||||||
|
r.callbacks['&'] = smartAmpRegularNBSP
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
r.callbacks['"'] = r.smartAngledDoubleQuote
|
r.callbacks['"'] = r.smartAngledDoubleQuote
|
||||||
r.callbacks['&'] = r.smartAmpAngledQuote
|
if !addNBSP {
|
||||||
|
r.callbacks['&'] = smartAmpAngled
|
||||||
|
} else {
|
||||||
|
r.callbacks['&'] = smartAmpAngledNBSP
|
||||||
|
}
|
||||||
}
|
}
|
||||||
r.callbacks['\''] = r.smartSingleQuote
|
r.callbacks['\''] = r.smartSingleQuote
|
||||||
r.callbacks['('] = r.smartParens
|
r.callbacks['('] = r.smartParens
|
||||||
|
Loading…
Reference in New Issue
Block a user