Skip to content

Commit

Permalink
Define EastAsianLineBreaksStyle to specify behavior of line breaking
Browse files Browse the repository at this point in the history
  • Loading branch information
henry0312 committed Sep 24, 2023
1 parent dc2230c commit 9d0b1b6
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 60 deletions.
42 changes: 21 additions & 21 deletions extension/cjk.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,31 @@ import (
// A CJKOption sets options for CJK support mostly for HTML based renderers.
type CJKOption func(*cjk)

// A EastAsianLineBreaksOption sets options for east asian line breaks.
type EastAsianLineBreaksOption func(*eastAsianLineBreaks)
// A EastAsianLineBreaksStyle is a style of east asian line breaks.
type EastAsianLineBreaksStyle int

const (
EastAsianLineBreaksStyleSimple EastAsianLineBreaksStyle = iota
EastAsianLineBreaksCSS3Draft
)

type EastAsianLineBreaksFunction func()

// WithEastAsianLineBreaks is a functional option that indicates whether softline breaks
// between east asian wide characters should be ignored.
func WithEastAsianLineBreaks(opts ...EastAsianLineBreaksOption) CJKOption {
func WithEastAsianLineBreaks(style ...EastAsianLineBreaksStyle) CJKOption {
return func(c *cjk) {
e := &eastAsianLineBreaks{
Enabled: true,
Enabled: true,
EastAsianLineBreaksStyle: EastAsianLineBreaksStyleSimple,
}
for _, opt := range opts {
opt(e)
for _, s := range style {
e.EastAsianLineBreaksStyle = s
}
c.EastAsianLineBreaks = e
}
}

// WithWorksEvenWithOneSide is a functional option that indicates that a softline break
// is ignored even if only one side of the break is east asian wide character.
func WithWorksEvenWithOneSide() EastAsianLineBreaksOption {
return func(e *eastAsianLineBreaks) {
e.WorksEvenWithOneSide = true
}
}

// WithEscapedSpace is a functional option that indicates that a '\' escaped half-space(0x20) should not be rendered.
func WithEscapedSpace() CJKOption {
return func(c *cjk) {
Expand All @@ -47,8 +47,8 @@ type cjk struct {
}

type eastAsianLineBreaks struct {
Enabled bool
WorksEvenWithOneSide bool
Enabled bool
EastAsianLineBreaksStyle EastAsianLineBreaksStyle
}

// CJK is a goldmark extension that provides functionalities for CJK languages.
Expand All @@ -66,13 +66,13 @@ func NewCJK(opts ...CJKOption) goldmark.Extender {
func (e *cjk) Extend(m goldmark.Markdown) {
if e.EastAsianLineBreaks != nil {
if e.EastAsianLineBreaks.Enabled {
opts := []html.EastAsianLineBreaksOption{}
if e.EastAsianLineBreaks.WorksEvenWithOneSide {
opts = append(opts, html.WithWorksEvenWithOneSide())
style := html.EastAsianLineBreaksStyleSimple
switch e.EastAsianLineBreaks.EastAsianLineBreaksStyle {
case EastAsianLineBreaksCSS3Draft:
style = html.EastAsianLineBreaksCSS3Draft
}
m.Renderer().AddOptions(html.WithEastAsianLineBreaks(opts...))
m.Renderer().AddOptions(html.WithEastAsianLineBreaks(style))
}

}
if e.EscapedSpace {
m.Renderer().AddOptions(html.WithWriter(html.NewWriter(html.WithEscapedSpace())))
Expand Down
4 changes: 2 additions & 2 deletions extension/cjk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,13 @@ func TestEastAsianLineBreaks(t *testing.T) {
t,
)

// WithWorksEvenWithOneSide option
// test with EastAsianLineBreaksCSS3Draft
markdown = goldmark.New(goldmark.WithRendererOptions(
html.WithXHTML(),
html.WithUnsafe(),
),
goldmark.WithExtensions(
NewCJK(WithEastAsianLineBreaks(WithWorksEvenWithOneSide())),
NewCJK(WithEastAsianLineBreaks(EastAsianLineBreaksCSS3Draft)),
),
)
no = 9
Expand Down
89 changes: 52 additions & 37 deletions renderer/html/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,52 +103,75 @@ func WithHardWraps() interface {
// EastAsianLineBreaks is an option name used in WithEastAsianLineBreaks.
const optEastAsianLineBreaks renderer.OptionName = "EastAsianLineBreaks"

type EastAsianLineBreaksStyle int

const (
EastAsianLineBreaksStyleSimple EastAsianLineBreaksStyle = iota
EastAsianLineBreaksCSS3Draft
)

type eastAsianLineBreaksFunction interface {
SoftLineBreak(thisLastRune rune, siblingFirstRune rune) bool
}

type eastAsianLineBreaksSimple struct{}

func (e *eastAsianLineBreaksSimple) SoftLineBreak(thisLastRune rune, siblingFirstRune rune) bool {
return !(util.IsEastAsianWideRune(thisLastRune) && util.IsEastAsianWideRune(siblingFirstRune))
}

type eastAsianLineBreaksCSS3Draft struct{}

func (e *eastAsianLineBreaksCSS3Draft) SoftLineBreak(thisLastRune rune, siblingFirstRune rune) bool {
return !(util.IsEastAsianWideRune(thisLastRune) || util.IsEastAsianWideRune(siblingFirstRune))
}

type eastAsianLineBreaks struct {
Enabled bool
WorksEvenWithOneSide bool
Enabled bool
EastAsianLineBreaksFunction eastAsianLineBreaksFunction
}

type withEastAsianLineBreaks struct {
worksEvenWithOneSide bool
eastAsianLineBreaksStyle EastAsianLineBreaksStyle
}

// A EastAsianLineBreaksOption sets options for east asian line breaks.
type EastAsianLineBreaksOption func(*withEastAsianLineBreaks)

func (o *withEastAsianLineBreaks) SetConfig(c *renderer.Config) {
c.Options[optEastAsianLineBreaks] = eastAsianLineBreaks{
Enabled: true,
WorksEvenWithOneSide: o.worksEvenWithOneSide,
switch o.eastAsianLineBreaksStyle {
case EastAsianLineBreaksStyleSimple:
c.Options[optEastAsianLineBreaks] = eastAsianLineBreaks{
Enabled: true,
EastAsianLineBreaksFunction: &eastAsianLineBreaksSimple{},
}
case EastAsianLineBreaksCSS3Draft:
c.Options[optEastAsianLineBreaks] = eastAsianLineBreaks{
Enabled: true,
EastAsianLineBreaksFunction: &eastAsianLineBreaksCSS3Draft{},
}
}
}

func (o *withEastAsianLineBreaks) SetHTMLOption(c *Config) {
c.EastAsianLineBreaks = eastAsianLineBreaks{
Enabled: true,
WorksEvenWithOneSide: o.worksEvenWithOneSide,
switch o.eastAsianLineBreaksStyle {
case EastAsianLineBreaksStyleSimple:
c.EastAsianLineBreaks = eastAsianLineBreaks{
Enabled: true,
EastAsianLineBreaksFunction: &eastAsianLineBreaksSimple{},
}
case EastAsianLineBreaksCSS3Draft:
c.EastAsianLineBreaks = eastAsianLineBreaks{
Enabled: true,
EastAsianLineBreaksFunction: &eastAsianLineBreaksCSS3Draft{},
}
}
}

// WithEastAsianLineBreaks is a functional option that indicates whether softline breaks
// between east asian wide characters should be ignored.
func WithEastAsianLineBreaks(opts ...EastAsianLineBreaksOption) interface {
func WithEastAsianLineBreaks(style EastAsianLineBreaksStyle) interface {
renderer.Option
Option
} {
w := &withEastAsianLineBreaks{}
for _, opt := range opts {
opt(w)
}

return w
}

// WithWorksEvenWithOneSide is a functional option that indicates that a softline break
// is ignored even if only one side of the break is east asian wide character.
func WithWorksEvenWithOneSide() EastAsianLineBreaksOption {
return func(o *withEastAsianLineBreaks) {
o.worksEvenWithOneSide = true
}
return &withEastAsianLineBreaks{style}
}

// XHTML is an option name used in WithXHTML.
Expand Down Expand Up @@ -697,16 +720,8 @@ func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, en
if siblingText := sibling.(*ast.Text).Text(source); len(siblingText) != 0 {
thisLastRune := util.ToRune(value, len(value)-1)
siblingFirstRune, _ := utf8.DecodeRune(siblingText)
if r.EastAsianLineBreaks.WorksEvenWithOneSide {
if !(util.IsEastAsianWideRune(thisLastRune) ||
util.IsEastAsianWideRune(siblingFirstRune)) {
_ = w.WriteByte('\n')
}
} else {
if !(util.IsEastAsianWideRune(thisLastRune) &&
util.IsEastAsianWideRune(siblingFirstRune)) {
_ = w.WriteByte('\n')
}
if r.EastAsianLineBreaks.EastAsianLineBreaksFunction.SoftLineBreak(thisLastRune, siblingFirstRune) {
_ = w.WriteByte('\n')
}
}
}
Expand Down

0 comments on commit 9d0b1b6

Please sign in to comment.