Skip to content

Commit

Permalink
Simplify EastAsianLineBreaks
Browse files Browse the repository at this point in the history
  • Loading branch information
yuin committed Oct 28, 2023
1 parent a89ad04 commit 9c90033
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 82 deletions.
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ linters-settings:
disabled: false
- name: dot-imports
severity: warning
disabled: false
disabled: true
- name: error-return
severity: warning
disabled: false
Expand Down
47 changes: 18 additions & 29 deletions extension/cjk.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,30 @@ import (
// A CJKOption sets options for CJK support mostly for HTML based renderers.
type CJKOption func(*cjk)

// A EastAsianLineBreaksStyle is a style of east asian line breaks.
type EastAsianLineBreaksStyle int
// A EastAsianLineBreaks is a style of east asian line breaks.
type EastAsianLineBreaks int

const (
// EastAsianLineBreaksStyleSimple is a style where soft line breaks are ignored
//EastAsianLineBreaksNone renders line breaks as it is.
EastAsianLineBreaksNone EastAsianLineBreaks = iota
// EastAsianLineBreaksSimple is a style where soft line breaks are ignored
// if both sides of the break are east asian wide characters.
EastAsianLineBreaksStyleSimple EastAsianLineBreaksStyle = iota
EastAsianLineBreaksSimple
// EastAsianLineBreaksCSS3Draft is a style where soft line breaks are ignored
// even if only one side of the break is an east asian wide character.
EastAsianLineBreaksCSS3Draft
)

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

Expand All @@ -44,38 +44,27 @@ func WithEscapedSpace() CJKOption {
}

type cjk struct {
EastAsianLineBreaks *eastAsianLineBreaks
EastAsianLineBreaks EastAsianLineBreaks
EscapedSpace bool
}

type eastAsianLineBreaks struct {
Enabled bool
EastAsianLineBreaksStyle EastAsianLineBreaksStyle
}

// CJK is a goldmark extension that provides functionalities for CJK languages.
var CJK = NewCJK(WithEastAsianLineBreaks(), WithEscapedSpace())

// NewCJK returns a new extension with given options.
func NewCJK(opts ...CJKOption) goldmark.Extender {
e := &cjk{}
e := &cjk{
EastAsianLineBreaks: EastAsianLineBreaksNone,
}
for _, opt := range opts {
opt(e)
}
return e
}

func (e *cjk) Extend(m goldmark.Markdown) {
if e.EastAsianLineBreaks != nil {
if e.EastAsianLineBreaks.Enabled {
style := html.EastAsianLineBreaksStyleSimple
switch e.EastAsianLineBreaks.EastAsianLineBreaksStyle {
case EastAsianLineBreaksCSS3Draft:
style = html.EastAsianLineBreaksCSS3Draft
}
m.Renderer().AddOptions(html.WithEastAsianLineBreaks(style))
}
}
m.Renderer().AddOptions(html.WithEastAsianLineBreaks(
html.EastAsianLineBreaks(e.EastAsianLineBreaks)))
if e.EscapedSpace {
m.Renderer().AddOptions(html.WithWriter(html.NewWriter(html.WithEscapedSpace())))
m.Parser().AddOptions(parser.WithEscapedSpace())
Expand Down
79 changes: 27 additions & 52 deletions renderer/html/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
type Config struct {
Writer Writer
HardWraps bool
EastAsianLineBreaks eastAsianLineBreaks
EastAsianLineBreaks EastAsianLineBreaks
XHTML bool
Unsafe bool
}
Expand All @@ -27,7 +27,7 @@ func NewConfig() Config {
return Config{
Writer: DefaultWriter,
HardWraps: false,
EastAsianLineBreaks: eastAsianLineBreaks{},
EastAsianLineBreaks: EastAsianLineBreaksNone,
XHTML: false,
Unsafe: false,
}
Expand All @@ -39,7 +39,7 @@ func (c *Config) SetOption(name renderer.OptionName, value interface{}) {
case optHardWraps:
c.HardWraps = value.(bool)
case optEastAsianLineBreaks:
c.EastAsianLineBreaks = value.(eastAsianLineBreaks)
c.EastAsianLineBreaks = value.(EastAsianLineBreaks)
case optXHTML:
c.XHTML = value.(bool)
case optUnsafe:
Expand Down Expand Up @@ -104,29 +104,31 @@ func WithHardWraps() interface {
// EastAsianLineBreaks is an option name used in WithEastAsianLineBreaks.
const optEastAsianLineBreaks renderer.OptionName = "EastAsianLineBreaks"

// A EastAsianLineBreaksStyle is a style of east asian line breaks.
type EastAsianLineBreaksStyle int
// A EastAsianLineBreaks is a style of east asian line breaks.
type EastAsianLineBreaks int

const (
// EastAsianLineBreaksStyleSimple follows east_asian_line_breaks in Pandoc.
EastAsianLineBreaksStyleSimple EastAsianLineBreaksStyle = iota
//EastAsianLineBreaksNone renders line breaks as it is.
EastAsianLineBreaksNone EastAsianLineBreaks = iota
// EastAsianLineBreaksSimple follows east_asian_line_breaks in Pandoc.
EastAsianLineBreaksSimple
// EastAsianLineBreaksCSS3Draft follows CSS text level3 "Segment Break Transformation Rules" with some enhancements.
EastAsianLineBreaksCSS3Draft
)

type eastAsianLineBreaker 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))
func (b EastAsianLineBreaks) softLineBreak(thisLastRune rune, siblingFirstRune rune) bool {
switch b {
case EastAsianLineBreaksNone:
return false
case EastAsianLineBreaksSimple:
return !(util.IsEastAsianWideRune(thisLastRune) && util.IsEastAsianWideRune(siblingFirstRune))
case EastAsianLineBreaksCSS3Draft:
return eastAsianLineBreaksCSS3DraftSoftLineBreak(thisLastRune, siblingFirstRune)
}
return false
}

type eastAsianLineBreaksCSS3Draft struct{}

func (e *eastAsianLineBreaksCSS3Draft) SoftLineBreak(thisLastRune rune, siblingFirstRune rune) bool {
func eastAsianLineBreaksCSS3DraftSoftLineBreak(thisLastRune rune, siblingFirstRune rune) bool {
// Implements CSS text level3 Segment Break Transformation Rules with some enhancements.
// References:
// - https://www.w3.org/TR/2020/WD-css-text-3-20200429/#line-break-transform
Expand Down Expand Up @@ -171,52 +173,25 @@ func (e *eastAsianLineBreaksCSS3Draft) SoftLineBreak(thisLastRune rune, siblingF
return true
}

type eastAsianLineBreaks struct {
Enabled bool
EastAsianLineBreaksFunction eastAsianLineBreaker
}

type withEastAsianLineBreaks struct {
eastAsianLineBreaksStyle EastAsianLineBreaksStyle
eastAsianLineBreaksStyle EastAsianLineBreaks
}

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

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

// WithEastAsianLineBreaks is a functional option that indicates whether softline breaks
// between east asian wide characters should be ignored.
func WithEastAsianLineBreaks(style EastAsianLineBreaksStyle) interface {
func WithEastAsianLineBreaks(e EastAsianLineBreaks) interface {
renderer.Option
Option
} {
return &withEastAsianLineBreaks{style}
return &withEastAsianLineBreaks{e}
}

// XHTML is an option name used in WithXHTML.
Expand Down Expand Up @@ -759,13 +734,13 @@ func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, en
_, _ = w.WriteString("<br>\n")
}
} else if n.SoftLineBreak() {
if r.EastAsianLineBreaks.Enabled && len(value) != 0 {
if r.EastAsianLineBreaks != EastAsianLineBreaksNone && len(value) != 0 {
sibling := node.NextSibling()
if sibling != nil && sibling.Kind() == ast.KindText {
if siblingText := sibling.(*ast.Text).Text(source); len(siblingText) != 0 {
thisLastRune := util.ToRune(value, len(value)-1)
siblingFirstRune, _ := utf8.DecodeRune(siblingText)
if r.EastAsianLineBreaks.EastAsianLineBreaksFunction.SoftLineBreak(thisLastRune, siblingFirstRune) {
if r.EastAsianLineBreaks.softLineBreak(thisLastRune, siblingFirstRune) {
_ = w.WriteByte('\n')
}
}
Expand Down

0 comments on commit 9c90033

Please sign in to comment.