From 33089e232f3ae65a718a0fc3b205ac5d89995885 Mon Sep 17 00:00:00 2001 From: yuin Date: Thu, 4 Jun 2020 15:26:01 +0900 Subject: [PATCH] Improve typographer --- extension/_test/typographer.txt | 7 ++++++ extension/typographer.go | 44 ++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/extension/_test/typographer.txt b/extension/_test/typographer.txt index 6155291..ef90bce 100644 --- a/extension/_test/typographer.txt +++ b/extension/_test/typographer.txt @@ -57,3 +57,10 @@ reported "issue 1 (IE-only)", "issue 2", 'issue3 (FF-only)', 'issue4' //- - - - - - - - -//

reported “issue 1 (IE-only)”, “issue 2”, ‘issue3 (FF-only)’, ‘issue4’

//= = = = = = = = = = = = = = = = = = = = = = = =// + +8: handle inches in qoutes +//- - - - - - - - -// +"Monitor 21"" and "Monitor"" +//- - - - - - - - -// +

“Monitor 21"” and “Monitor”"

+//= = = = = = = = = = = = = = = = = = = = = = = =// diff --git a/extension/typographer.go b/extension/typographer.go index caaae9a..8e95231 100644 --- a/extension/typographer.go +++ b/extension/typographer.go @@ -10,6 +10,27 @@ import ( "github.com/yuin/goldmark/util" ) +var uncloseCounterKey = parser.NewContextKey() + +type unclosedCounter struct { + Single int + Double int +} + +func (u *unclosedCounter) Reset() { + u.Single = 0 + u.Double = 0 +} + +func getUnclosedCounter(pc parser.Context) *unclosedCounter { + v := pc.Get(uncloseCounterKey) + if v == nil { + v = &unclosedCounter{} + pc.Set(uncloseCounterKey, v) + } + return v.(*unclosedCounter) +} + // TypographicPunctuation is a key of the punctuations that can be replaced with // typographic entities. type TypographicPunctuation int @@ -193,6 +214,7 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser if d == nil { return nil } + counter := getUnclosedCounter(pc) if c == '\'' { if s.Substitutions[Apostrophe] != nil { // Handle decade abbrevations such as '90s @@ -227,43 +249,47 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser if len(line) > 2 && ((line[1] == 'v' && line[2] == 'e') || (line[1] == 'l' && line[2] == 'l') || (line[1] == 'r' && line[2] == 'e')) && (len(line) < 4 || util.IsPunct(line[3]) || util.IsSpace(line[3])) { nt = RightSingleQuote } + if nt == LeftSingleQuote { + counter.Single++ + } node := gast.NewString(s.Substitutions[nt]) node.SetCode(true) block.Advance(1) return node } - if s.Substitutions[RightSingleQuote] != nil { + 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]))) if isClose || maybeClose { node := gast.NewString(s.Substitutions[RightSingleQuote]) node.SetCode(true) block.Advance(1) + counter.Single-- return node } } } if c == '"' { - // special case: 7'1"" - if len(line) > 1 && line[1] == '"' && unicode.IsDigit(before) { - node := gast.NewString(line[0:2]) - block.Advance(2) - return node - } if s.Substitutions[LeftDoubleQuote] != nil && d.CanOpen && !d.CanClose { node := gast.NewString(s.Substitutions[LeftDoubleQuote]) node.SetCode(true) block.Advance(1) + counter.Double++ return node } - if s.Substitutions[RightDoubleQuote] != nil { + 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]))) if isClose || maybeClose { + // special case: "Monitor 21"" + if len(line) > 1 && line[1] == '"' && unicode.IsDigit(before) { + return nil + } node := gast.NewString(s.Substitutions[RightDoubleQuote]) node.SetCode(true) block.Advance(1) + counter.Double-- return node } } @@ -273,7 +299,7 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser } func (s *typographerParser) CloseBlock(parent gast.Node, pc parser.Context) { - // nothing to do + getUnclosedCounter(pc).Reset() } type typographer struct {