summaryrefslogtreecommitdiff
path: root/vendor/github.com/yuin/goldmark/extension/typographer.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/yuin/goldmark/extension/typographer.go')
-rw-r--r--vendor/github.com/yuin/goldmark/extension/typographer.go348
1 files changed, 0 insertions, 348 deletions
diff --git a/vendor/github.com/yuin/goldmark/extension/typographer.go b/vendor/github.com/yuin/goldmark/extension/typographer.go
deleted file mode 100644
index 44c15ebf1..000000000
--- a/vendor/github.com/yuin/goldmark/extension/typographer.go
+++ /dev/null
@@ -1,348 +0,0 @@
-package extension
-
-import (
- "unicode"
-
- "github.com/yuin/goldmark"
- gast "github.com/yuin/goldmark/ast"
- "github.com/yuin/goldmark/parser"
- "github.com/yuin/goldmark/text"
- "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
-
-const (
- // LeftSingleQuote is ' .
- LeftSingleQuote TypographicPunctuation = iota + 1
- // RightSingleQuote is ' .
- RightSingleQuote
- // LeftDoubleQuote is " .
- LeftDoubleQuote
- // RightDoubleQuote is " .
- RightDoubleQuote
- // EnDash is -- .
- EnDash
- // EmDash is --- .
- EmDash
- // Ellipsis is ... .
- Ellipsis
- // LeftAngleQuote is << .
- LeftAngleQuote
- // RightAngleQuote is >> .
- RightAngleQuote
- // Apostrophe is ' .
- Apostrophe
-
- typographicPunctuationMax
-)
-
-// An TypographerConfig struct is a data structure that holds configuration of the
-// Typographer extension.
-type TypographerConfig struct {
- Substitutions [][]byte
-}
-
-func newDefaultSubstitutions() [][]byte {
- replacements := make([][]byte, typographicPunctuationMax)
- replacements[LeftSingleQuote] = []byte("&lsquo;")
- replacements[RightSingleQuote] = []byte("&rsquo;")
- replacements[LeftDoubleQuote] = []byte("&ldquo;")
- replacements[RightDoubleQuote] = []byte("&rdquo;")
- replacements[EnDash] = []byte("&ndash;")
- replacements[EmDash] = []byte("&mdash;")
- replacements[Ellipsis] = []byte("&hellip;")
- replacements[LeftAngleQuote] = []byte("&laquo;")
- replacements[RightAngleQuote] = []byte("&raquo;")
- replacements[Apostrophe] = []byte("&rsquo;")
-
- return replacements
-}
-
-// SetOption implements SetOptioner.
-func (b *TypographerConfig) SetOption(name parser.OptionName, value interface{}) {
- switch name {
- case optTypographicSubstitutions:
- b.Substitutions = value.([][]byte)
- }
-}
-
-// A TypographerOption interface sets options for the TypographerParser.
-type TypographerOption interface {
- parser.Option
- SetTypographerOption(*TypographerConfig)
-}
-
-const optTypographicSubstitutions parser.OptionName = "TypographicSubstitutions"
-
-// TypographicSubstitutions is a list of the substitutions for the Typographer extension.
-type TypographicSubstitutions map[TypographicPunctuation][]byte
-
-type withTypographicSubstitutions struct {
- value [][]byte
-}
-
-func (o *withTypographicSubstitutions) SetParserOption(c *parser.Config) {
- c.Options[optTypographicSubstitutions] = o.value
-}
-
-func (o *withTypographicSubstitutions) SetTypographerOption(p *TypographerConfig) {
- p.Substitutions = o.value
-}
-
-// WithTypographicSubstitutions is a functional otpion that specify replacement text
-// for punctuations.
-func WithTypographicSubstitutions[T []byte | string](values map[TypographicPunctuation]T) TypographerOption {
- replacements := newDefaultSubstitutions()
- for k, v := range values {
- replacements[k] = []byte(v)
- }
-
- return &withTypographicSubstitutions{replacements}
-}
-
-type typographerDelimiterProcessor struct {
-}
-
-func (p *typographerDelimiterProcessor) IsDelimiter(b byte) bool {
- return b == '\'' || b == '"'
-}
-
-func (p *typographerDelimiterProcessor) CanOpenCloser(opener, closer *parser.Delimiter) bool {
- return opener.Char == closer.Char
-}
-
-func (p *typographerDelimiterProcessor) OnMatch(consumes int) gast.Node {
- return nil
-}
-
-var defaultTypographerDelimiterProcessor = &typographerDelimiterProcessor{}
-
-type typographerParser struct {
- TypographerConfig
-}
-
-// NewTypographerParser return a new InlineParser that parses
-// typographer expressions.
-func NewTypographerParser(opts ...TypographerOption) parser.InlineParser {
- p := &typographerParser{
- TypographerConfig: TypographerConfig{
- Substitutions: newDefaultSubstitutions(),
- },
- }
- for _, o := range opts {
- o.SetTypographerOption(&p.TypographerConfig)
- }
- return p
-}
-
-func (s *typographerParser) Trigger() []byte {
- return []byte{'\'', '"', '-', '.', ',', '<', '>', '*', '['}
-}
-
-func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node {
- line, _ := block.PeekLine()
- c := line[0]
- if len(line) > 2 {
- if c == '-' {
- if s.Substitutions[EmDash] != nil && line[1] == '-' && line[2] == '-' { // ---
- node := gast.NewString(s.Substitutions[EmDash])
- node.SetCode(true)
- block.Advance(3)
- return node
- }
- } else if c == '.' {
- if s.Substitutions[Ellipsis] != nil && line[1] == '.' && line[2] == '.' { // ...
- node := gast.NewString(s.Substitutions[Ellipsis])
- node.SetCode(true)
- block.Advance(3)
- return node
- }
- return nil
- }
- }
- if len(line) > 1 {
- if c == '<' {
- if s.Substitutions[LeftAngleQuote] != nil && line[1] == '<' { // <<
- node := gast.NewString(s.Substitutions[LeftAngleQuote])
- node.SetCode(true)
- block.Advance(2)
- return node
- }
- return nil
- } else if c == '>' {
- if s.Substitutions[RightAngleQuote] != nil && line[1] == '>' { // >>
- node := gast.NewString(s.Substitutions[RightAngleQuote])
- node.SetCode(true)
- block.Advance(2)
- return node
- }
- return nil
- } else if s.Substitutions[EnDash] != nil && c == '-' && line[1] == '-' { // --
- node := gast.NewString(s.Substitutions[EnDash])
- node.SetCode(true)
- block.Advance(2)
- return node
- }
- }
- if c == '\'' || c == '"' {
- before := block.PrecendingCharacter()
- d := parser.ScanDelimiter(line, before, 1, defaultTypographerDelimiterProcessor)
- if d == nil {
- return nil
- }
- counter := getUnclosedCounter(pc)
- if c == '\'' {
- if s.Substitutions[Apostrophe] != nil {
- // Handle decade abbrevations such as '90s
- if d.CanOpen && !d.CanClose && len(line) > 3 &&
- util.IsNumeric(line[1]) && util.IsNumeric(line[2]) && line[3] == 's' {
- after := rune(' ')
- if len(line) > 4 {
- after = util.ToRune(line, 4)
- }
- if len(line) == 3 || util.IsSpaceRune(after) || util.IsPunctRune(after) {
- node := gast.NewString(s.Substitutions[Apostrophe])
- node.SetCode(true)
- block.Advance(1)
- 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))) {
- node := gast.NewString(s.Substitutions[Apostrophe])
- node.SetCode(true)
- block.Advance(1)
- return node
- }
- }
- if s.Substitutions[LeftSingleQuote] != nil && d.CanOpen && !d.CanClose {
- nt := LeftSingleQuote
- // 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
- }
- // special cases: I've, I'll, You're
- 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 {
- // plural possesive 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 && 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)
- block.Advance(1)
- counter.Single--
- return node
- }
- }
- }
- if c == '"' {
- 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 && counter.Double > 0 {
- isClose := d.CanClose && !d.CanOpen
- 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) {
- return nil
- }
- node := gast.NewString(s.Substitutions[RightDoubleQuote])
- node.SetCode(true)
- block.Advance(1)
- counter.Double--
- return node
- }
- }
- }
- }
- return nil
-}
-
-func (s *typographerParser) CloseBlock(parent gast.Node, pc parser.Context) {
- getUnclosedCounter(pc).Reset()
-}
-
-type typographer struct {
- options []TypographerOption
-}
-
-// Typographer is an extension that replaces punctuations with typographic entities.
-var Typographer = &typographer{}
-
-// NewTypographer returns a new Extender that replaces punctuations with typographic entities.
-func NewTypographer(opts ...TypographerOption) goldmark.Extender {
- return &typographer{
- options: opts,
- }
-}
-
-func (e *typographer) Extend(m goldmark.Markdown) {
- m.Parser().AddOptions(parser.WithInlineParsers(
- util.Prioritized(NewTypographerParser(e.options...), 9999),
- ))
-}