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,