From 857a1a0260be14ca4a45c4236e6f712e4c2256ae Mon Sep 17 00:00:00 2001 From: bep Date: Wed, 5 Nov 2014 23:18:32 +0100 Subject: [PATCH] Add support for angled, double quotes The flag `HTML_SMARTYPANTS_ANGLED_QUOTES` combined with `HTML_USE_SMARTYPANTS` configures rendering of double quotes as angled left and right quotes (« »). The SmartyPants documentation mentions a special syntax for these, `<<>>`, a syntax neither pretty nor user friendly. Typical use cases would be either or, or combined, but never in the same document. As an example would be a person from Norway; he has a blog in both English and Norwegian (his native tounge); he would then configure Blackfriday to use angled quotes for the Norwegian section, but keep them as reqular double quotes for the English. If the flag `HTML_SMARTYPANTS_ANGLED_QUOTES` is not provided, everything works as before this commit. --- html.go | 1 + inline_test.go | 24 ++++++++++++++++++++++++ smartypants.go | 33 +++++++++++++++++++++++++++------ 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/html.go b/html.go index a85f918..e679db9 100644 --- a/html.go +++ b/html.go @@ -39,6 +39,7 @@ const ( HTML_USE_SMARTYPANTS // enable smart punctuation substitutions HTML_SMARTYPANTS_FRACTIONS // enable smart fractions (with HTML_USE_SMARTYPANTS) HTML_SMARTYPANTS_LATEX_DASHES // enable LaTeX-style dashes (with HTML_USE_SMARTYPANTS) + HTML_SMARTYPANTS_ANGLED_QUOTES // enable angled double quotes (with HTML_USE_SMARTYPANTS) for double quotes rendering HTML_FOOTNOTE_RETURN_LINKS // generate a link at the end of a footnote to return to the source ) diff --git a/inline_test.go b/inline_test.go index 798fed4..7ad3f0d 100644 --- a/inline_test.go +++ b/inline_test.go @@ -798,3 +798,27 @@ func TestFootnotesWithParameters(t *testing.T) { doTestsInlineParam(t, tests, EXTENSION_FOOTNOTES, HTML_FOOTNOTE_RETURN_LINKS, params) } + +func TestSmartDoubleQuotes(t *testing.T) { + var tests = []string{ + "this should be normal \"quoted\" text.\n", + "

this should be normal “quoted” text.

\n", + "this \" single double\n", + "

this “ single double

\n", + "two pair of \"some\" quoted \"text\".\n", + "

two pair of “some” quoted “text”.

\n"} + + doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS, HtmlRendererParameters{}) +} + +func TestSmartAngledDoubleQuotes(t *testing.T) { + var tests = []string{ + "this should be angled \"quoted\" text.\n", + "

this should be angled «quoted» text.

\n", + "this \" single double\n", + "

this « single double

\n", + "two pair of \"some\" quoted \"text\".\n", + "

two pair of «some» quoted «text».

\n"} + + doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_ANGLED_QUOTES, HtmlRendererParameters{}) +} diff --git a/smartypants.go b/smartypants.go index d6f4ad9..38ffcf7 100644 --- a/smartypants.go +++ b/smartypants.go @@ -205,13 +205,13 @@ func smartDashLatex(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, return 0 } -func smartAmp(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { +func smartAmpVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int { if bytes.HasPrefix(text, []byte(""")) { nextChar := byte(0) if len(text) >= 7 { nextChar = text[6] } - if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) { + if smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) { return 5 } } @@ -224,6 +224,14 @@ func smartAmp(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text return 0 } +func smartAmp(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { + return smartAmpVariant(out, smrt, previousChar, text, 'd') +} + +func smartAmpAngledQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { + return smartAmpVariant(out, smrt, previousChar, text, 'a') +} + func smartPeriod(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { if len(text) >= 3 && text[1] == '.' && text[2] == '.' { out.WriteString("…") @@ -323,18 +331,26 @@ func smartNumber(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, te return 0 } -func smartDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { +func smartDoubleQuoteVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int { nextChar := byte(0) if len(text) > 1 { nextChar = text[1] } - if !smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) { + if !smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) { out.WriteString(""") } return 0 } +func smartDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { + return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'd') +} + +func smartAngledDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { + return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'a') +} + func smartLeftAngle(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { i := 0 @@ -352,8 +368,13 @@ type smartypantsRenderer [256]smartCallback func smartypants(flags int) *smartypantsRenderer { r := new(smartypantsRenderer) - r['"'] = smartDoubleQuote - r['&'] = smartAmp + if flags&HTML_SMARTYPANTS_ANGLED_QUOTES == 0 { + r['"'] = smartDoubleQuote + r['&'] = smartAmp + } else { + r['"'] = smartAngledDoubleQuote + r['&'] = smartAmpAngledQuote + } r['\''] = smartSingleQuote r['('] = smartParens if flags&HTML_SMARTYPANTS_LATEX_DASHES == 0 {