From 68dcec6ac4bb1b8e3986e65ea7cf00958414d815 Mon Sep 17 00:00:00 2001 From: yuin Date: Mon, 2 Dec 2019 14:38:28 +0900 Subject: [PATCH] Closes #46 : Add WithIDs option --- extra_test.go | 27 +++++++++++++++++++++++++++ parser/parser.go | 29 +++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/extra_test.go b/extra_test.go index a794211..89482a3 100644 --- a/extra_test.go +++ b/extra_test.go @@ -5,6 +5,7 @@ import ( "testing" . "github.com/yuin/goldmark" + "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer/html" "github.com/yuin/goldmark/testutil" ) @@ -57,3 +58,29 @@ func TestWindowsNewLine(t *testing.T) { t.Errorf("\n%s\n---------\n%s", source, b2.String()) } } + +type myIDs struct { +} + +func (s *myIDs) Generate(value, prefix []byte) []byte { + return []byte("my-id") +} + +func (s *myIDs) Put(value []byte) { +} + +func TestAutogeneratedIDs(t *testing.T) { + ctx := parser.NewContext(parser.WithIDs(&myIDs{})) + markdown := New(WithParserOptions(parser.WithAutoHeadingID())) + source := []byte("# Title1\n## Title2") + var b bytes.Buffer + err := markdown.Convert(source, &b, parser.WithContext(ctx)) + if err != nil { + t.Error(err.Error()) + } + if b.String() != `

Title1

+

Title2

+` { + t.Errorf("%s\n---------\n%s", source, b.String()) + } +} diff --git a/parser/parser.go b/parser/parser.go index 1d9487a..b536fd5 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -88,7 +88,7 @@ func (s *ids) Generate(value, prefix []byte) []byte { v += 'a' - 'A' } result = append(result, v) - } else if util.IsSpace(v) { + } else if util.IsSpace(v) || v == '-' || v == '_' { result = append(result, '-') } } @@ -104,7 +104,7 @@ func (s *ids) Generate(value, prefix []byte) []byte { return result } for i := 1; ; i++ { - newResult := fmt.Sprintf("%s%d", result, i) + newResult := fmt.Sprintf("%s-%d", result, i) if _, ok := s.values[newResult]; !ok { s.values[newResult] = true return []byte(newResult) @@ -198,6 +198,20 @@ type Context interface { LastOpenedBlock() Block } +// A ContextConfig struct is a data structure that holds configuration of the Context. +type ContextConfig struct { + IDs IDs +} + +// An ContextOption is a functional option type for the Context. +type ContextOption func(*ContextConfig) + +func WithIDs(ids IDs) ContextOption { + return func(c *ContextConfig) { + c.IDs = ids + } +} + type parseContext struct { store []interface{} ids IDs @@ -210,11 +224,18 @@ type parseContext struct { } // NewContext returns a new Context. -func NewContext() Context { +func NewContext(options ...ContextOption) Context { + cfg := &ContextConfig{ + IDs: newIDs(), + } + for _, option := range options { + option(cfg) + } + return &parseContext{ store: make([]interface{}, ContextKeyMax+1), refs: map[string]Reference{}, - ids: newIDs(), + ids: cfg.IDs, blockOffset: -1, blockIndent: -1, delimiters: nil,