Skip to content

Commit

Permalink
Merge pull request #280 from natemoo-re/fix/typographer
Browse files Browse the repository at this point in the history
Improve Typographer Edge Cases
  • Loading branch information
yuin committed Feb 18, 2022
2 parents b7b0919 + 7aa0ead commit 1def545
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 4 deletions.
70 changes: 70 additions & 0 deletions extension/_test/typographer.txt
Expand Up @@ -64,3 +64,73 @@ reported "issue 1 (IE-only)", "issue 2", 'issue3 (FF-only)', 'issue4'
//- - - - - - - - -//
<p>&ldquo;Monitor 21&quot;&rdquo; and &ldquo;Monitor&rdquo;&quot;</p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

9: Closing quotation marks within italics
//- - - - - - - - -//
*"At first, things were not clear."*
//- - - - - - - - -//
<p><em>&ldquo;At first, things were not clear.&rdquo;</em></p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

10: Closing quotation marks within boldfacing
//- - - - - - - - -//
**"At first, things were not clear."**
//- - - - - - - - -//
<p><strong>&ldquo;At first, things were not clear.&rdquo;</strong></p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

11: Closing quotation marks within boldfacing and italics
//- - - - - - - - -//
***"At first, things were not clear."***
//- - - - - - - - -//
<p><em><strong>&ldquo;At first, things were not clear.&rdquo;</strong></em></p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

12: Closing quotation marks within boldfacing and italics
//- - - - - - - - -//
***"At first, things were not clear."***
//- - - - - - - - -//
<p><em><strong>&ldquo;At first, things were not clear.&rdquo;</strong></em></p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

13: Plural possessives
//- - - - - - - - -//
John's dog is named Sam. The Smiths' dog is named Rover.
//- - - - - - - - -//
<p>John&rsquo;s dog is named Sam. The Smiths&rsquo; dog is named Rover.</p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

14: Links within quotation marks and parenthetical phrases
//- - - - - - - - -//
This is not difficult (see "[Introduction to Hugo Templating](https://gohugo.io/templates/introduction/)").
//- - - - - - - - -//
<p>This is not difficult (see &ldquo;<a href="https://gohugo.io/templates/introduction/">Introduction to Hugo Templating</a>&rdquo;).</p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

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)
//- - - - - - - - -//
<p>Apple&rsquo;s early Cairo font gave us <a href="https://www.macworld.com/article/2926184/we-miss-you-clarus-the-dogcow.html">&ldquo;moof&rdquo; and the &ldquo;dogcow.&rdquo;</a></p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

16: Single closing quotation marks with slang/informalities
//- - - - - - - - -//
"I'm not doin' that," Bill said with emphasis.
//- - - - - - - - -//
<p>&ldquo;I&rsquo;m not doin&rsquo; that,&rdquo; Bill said with emphasis.</p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

17: Closing single quotation marks in quotations-within-quotations
//- - - - - - - - -//
Janet said, "When everything is 'breaking news,' nothing is 'breaking news.'"
//- - - - - - - - -//
<p>Janet said, &ldquo;When everything is &lsquo;breaking news,&rsquo; nothing is &lsquo;breaking news.&rsquo;&rdquo;</p>
//= = = = = = = = = = = = = = = = = = = = = = = =//

18: Opening single quotation marks for abbreviations
//- - - - - - - - -//
We're talking about the internet --- 'net for short. Let's rock 'n roll!
//- - - - - - - - -//
<p>We&rsquo;re talking about the internet &mdash; &rsquo;net for short. Let&rsquo;s rock &rsquo;n roll!</p>
//= = = = = = = = = = = = = = = = = = = = = = = =//
24 changes: 20 additions & 4 deletions extension/typographer.go
Expand Up @@ -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 {
Expand Down Expand Up @@ -230,6 +230,13 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser
return node
}
}
// special cases: 'twas, 'em, 'net
if len(line) > 1 && (unicode.IsPunct(before) || unicode.IsSpace(before)) && (line[1] == 't' || line[1] == 'e' || line[1] == 'n' || line[1] == 'l') {
node := gast.NewString(s.Substitutions[Apostrophe])
node.SetCode(true)
block.Advance(1)
return node
}
// Convert normal apostrophes. This is probably more flexible than necessary but
// converts any apostrophe in between two alphanumerics.
if len(line) > 1 && (unicode.IsDigit(before) || unicode.IsLetter(before)) && (unicode.IsLetter(util.ToRune(line, 1))) {
Expand All @@ -241,7 +248,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
}
Expand All @@ -258,9 +265,18 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser
block.Advance(1)
return node
}
if s.Substitutions[RightSingleQuote] != nil {
// plural possesives and abbreviations: Smiths', doin'
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)
Expand All @@ -280,7 +296,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) {
Expand Down

0 comments on commit 1def545

Please sign in to comment.