From 7b616a4c803bb3c8bb3f9d7540e8123c1d5a87f6 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Thu, 17 Feb 2022 09:41:29 -0600 Subject: [PATCH] fix typographer single quote edge cases --- extension/_test/typographer.txt | 26 ++++++++++---------------- extension/typographer.go | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/extension/_test/typographer.txt b/extension/_test/typographer.txt index 7534d83..af6c1cb 100644 --- a/extension/_test/typographer.txt +++ b/extension/_test/typographer.txt @@ -69,75 +69,69 @@ reported "issue 1 (IE-only)", "issue 2", 'issue3 (FF-only)', 'issue4' //- - - - - - - - -// *"At first, things were not clear."* //- - - - - - - - -// -“At first, things were not clear.” +

“At first, things were not clear.”

//= = = = = = = = = = = = = = = = = = = = = = = =// 10: Closing quotation marks within boldfacing //- - - - - - - - -// **"At first, things were not clear."** //- - - - - - - - -// -“At first, things were not clear.” +

“At first, things were not clear.”

//= = = = = = = = = = = = = = = = = = = = = = = =// 11: Closing quotation marks within boldfacing and italics //- - - - - - - - -// ***"At first, things were not clear."*** //- - - - - - - - -// -“At first, things were not clear.” +

“At first, things were not clear.”

//= = = = = = = = = = = = = = = = = = = = = = = =// 12: Closing quotation marks within boldfacing and italics //- - - - - - - - -// ***"At first, things were not clear."*** //- - - - - - - - -// -“At first, things were not clear.” +

“At first, things were not clear.”

//= = = = = = = = = = = = = = = = = = = = = = = =// 13: Plural possessives //- - - - - - - - -// John's dog is named Sam. The Smiths' dog is named Rover. //- - - - - - - - -// -John’s dog is named Sam. The Smiths’ dog is named Rover. +

John’s dog is named Sam. The Smiths’ dog is named Rover.

//= = = = = = = = = = = = = = = = = = = = = = = =// 14: Links within quotation marks and parenthetical phrases //- - - - - - - - -// This is not difficult (see "[Introduction to Hugo Templating](https://gohugo.io/templates/introduction/)"). //- - - - - - - - -// -This is not difficult (see “[Introduction to Hugo Templating](https://gohugo.io/templates/introduction/)”). +

This is not difficult (see “Introduction to Hugo Templating”).

//= = = = = = = = = = = = = = = = = = = = = = = =// 15: Quotation marks within links //- - - - - - - - -// Apple's early Cairo font gave us ["moof" and the "dogcow."](https://www.macworld.com/article/2926184/we-miss-you-clarus-the-dogcow.html) //- - - - - - - - -// -Apple’s early Cairo font gave us “moof” and the “dogcow.” +

Apple’s early Cairo font gave us “moof” and the “dogcow.”

//= = = = = = = = = = = = = = = = = = = = = = = =// 16: Single closing quotation marks with slang/informalities //- - - - - - - - -// "I'm not doin' that," Bill said with emphasis. //- - - - - - - - -// -“I’m not doin’ that,” Bill said with emphasis. +

“I’m not doin’ that,” Bill said with emphasis.

//= = = = = = = = = = = = = = = = = = = = = = = =// 17: Closing single quotation marks in quotations-within-quotations //- - - - - - - - -// Janet said, "When everything is 'breaking news,' nothing is 'breaking news.'" //- - - - - - - - -// -Janet said, “When everything is ‘breaking news,’ nothing is ‘breaking news.’” +

Janet said, “When everything is ‘breaking news,’ nothing is ‘breaking news.’”

//= = = = = = = = = = = = = = = = = = = = = = = =// 18: Opening single quotation marks for abbreviations //- - - - - - - - -// We're talking about the internet --- 'net for short. //- - - - - - - - -// -We’re talking about the internet — ’net for short. +

We’re talking about the internet — ’net for short.

//= = = = = = = = = = = = = = = = = = = = = = = =// -19: Quotation marks next to footnotes -//- - - - - - - - -// -People ask, "Why can't you just change the format?"[^formatChgNote] -//- - - - - - - - -// -People ask, “Why can’t you just change the format?”1 -//= = = = = = = = = = = = = = = = = = = = = = = =// diff --git a/extension/typographer.go b/extension/typographer.go index 2c34730..4a57ba4 100644 --- a/extension/typographer.go +++ b/extension/typographer.go @@ -160,7 +160,7 @@ func NewTypographerParser(opts ...TypographerOption) parser.InlineParser { } func (s *typographerParser) Trigger() []byte { - return []byte{'\'', '"', '-', '.', '<', '>'} + return []byte{'\'', '"', '-', '.', ',', '<', '>', '*', '['} } func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { @@ -241,7 +241,7 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser } if s.Substitutions[LeftSingleQuote] != nil && d.CanOpen && !d.CanClose { nt := LeftSingleQuote - // special cases: Alice's, I'm ,Don't, You'd + // special cases: Alice's, I'm, Don't, You'd if len(line) > 1 && (line[1] == 's' || line[1] == 'm' || line[1] == 't' || line[1] == 'd') && (len(line) < 3 || util.IsPunct(line[2]) || util.IsSpace(line[2])) { nt = RightSingleQuote } @@ -258,9 +258,17 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser block.Advance(1) return node } + if s.Substitutions[RightSingleQuote] != nil { + if len(line) > 1 && unicode.IsSpace(util.ToRune(line, 0)) || unicode.IsPunct(util.ToRune(line, 0)) && (len(line) > 2 && !unicode.IsDigit(util.ToRune(line, 1))) { + node := gast.NewString(s.Substitutions[RightSingleQuote]) + node.SetCode(true) + block.Advance(1) + return node + } + } if s.Substitutions[RightSingleQuote] != nil && counter.Single > 0 { isClose := d.CanClose && !d.CanOpen - maybeClose := d.CanClose && d.CanOpen && len(line) > 1 && (line[1] == ',' || line[1] == '.' || line[1] == '!' || line[1] == '?') && (len(line) == 2 || (len(line) > 2 && util.IsPunct(line[2]) || util.IsSpace(line[2]))) + maybeClose := d.CanClose && d.CanOpen && len(line) > 1 && unicode.IsPunct(util.ToRune(line, 1)) && (len(line) == 2 || (len(line) > 2 && util.IsPunct(line[2]) || util.IsSpace(line[2]))) if isClose || maybeClose { node := gast.NewString(s.Substitutions[RightSingleQuote]) node.SetCode(true) @@ -280,7 +288,7 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser } if s.Substitutions[RightDoubleQuote] != nil && counter.Double > 0 { isClose := d.CanClose && !d.CanOpen - maybeClose := d.CanClose && d.CanOpen && len(line) > 1 && (line[1] == ',' || line[1] == '.' || line[1] == '!' || line[1] == '?') && (len(line) == 2 || (len(line) > 2 && util.IsPunct(line[2]) || util.IsSpace(line[2]))) + maybeClose := d.CanClose && d.CanOpen && len(line) > 1 && (unicode.IsPunct(util.ToRune(line, 1))) && (len(line) == 2 || (len(line) > 2 && util.IsPunct(line[2]) || util.IsSpace(line[2]))) if isClose || maybeClose { // special case: "Monitor 21"" if len(line) > 1 && line[1] == '"' && unicode.IsDigit(before) {