Simplify EastAsianLineBreaks

This commit is contained in:
yuin 2023-10-28 17:57:55 +09:00
parent a89ad04c49
commit 9c9003363f
3 changed files with 46 additions and 82 deletions

View file

@ -45,7 +45,7 @@ linters-settings:
disabled: false disabled: false
- name: dot-imports - name: dot-imports
severity: warning severity: warning
disabled: false disabled: true
- name: error-return - name: error-return
severity: warning severity: warning
disabled: false disabled: false

View file

@ -9,13 +9,15 @@ import (
// A CJKOption sets options for CJK support mostly for HTML based renderers. // A CJKOption sets options for CJK support mostly for HTML based renderers.
type CJKOption func(*cjk) type CJKOption func(*cjk)
// A EastAsianLineBreaksStyle is a style of east asian line breaks. // A EastAsianLineBreaks is a style of east asian line breaks.
type EastAsianLineBreaksStyle int type EastAsianLineBreaks int
const ( 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. // 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 // EastAsianLineBreaksCSS3Draft is a style where soft line breaks are ignored
// even if only one side of the break is an east asian wide character. // even if only one side of the break is an east asian wide character.
EastAsianLineBreaksCSS3Draft EastAsianLineBreaksCSS3Draft
@ -23,16 +25,14 @@ const (
// WithEastAsianLineBreaks is a functional option that indicates whether softline breaks // WithEastAsianLineBreaks is a functional option that indicates whether softline breaks
// between east asian wide characters should be ignored. // 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) { return func(c *cjk) {
e := &eastAsianLineBreaks{ if len(style) == 0 {
Enabled: true, c.EastAsianLineBreaks = EastAsianLineBreaksSimple
EastAsianLineBreaksStyle: EastAsianLineBreaksStyleSimple, return
} }
for _, s := range style { c.EastAsianLineBreaks = style[0]
e.EastAsianLineBreaksStyle = s
}
c.EastAsianLineBreaks = e
} }
} }
@ -44,21 +44,18 @@ func WithEscapedSpace() CJKOption {
} }
type cjk struct { type cjk struct {
EastAsianLineBreaks *eastAsianLineBreaks EastAsianLineBreaks EastAsianLineBreaks
EscapedSpace bool EscapedSpace bool
} }
type eastAsianLineBreaks struct {
Enabled bool
EastAsianLineBreaksStyle EastAsianLineBreaksStyle
}
// CJK is a goldmark extension that provides functionalities for CJK languages. // CJK is a goldmark extension that provides functionalities for CJK languages.
var CJK = NewCJK(WithEastAsianLineBreaks(), WithEscapedSpace()) var CJK = NewCJK(WithEastAsianLineBreaks(), WithEscapedSpace())
// NewCJK returns a new extension with given options. // NewCJK returns a new extension with given options.
func NewCJK(opts ...CJKOption) goldmark.Extender { func NewCJK(opts ...CJKOption) goldmark.Extender {
e := &cjk{} e := &cjk{
EastAsianLineBreaks: EastAsianLineBreaksNone,
}
for _, opt := range opts { for _, opt := range opts {
opt(e) opt(e)
} }
@ -66,16 +63,8 @@ func NewCJK(opts ...CJKOption) goldmark.Extender {
} }
func (e *cjk) Extend(m goldmark.Markdown) { func (e *cjk) Extend(m goldmark.Markdown) {
if e.EastAsianLineBreaks != nil { m.Renderer().AddOptions(html.WithEastAsianLineBreaks(
if e.EastAsianLineBreaks.Enabled { html.EastAsianLineBreaks(e.EastAsianLineBreaks)))
style := html.EastAsianLineBreaksStyleSimple
switch e.EastAsianLineBreaks.EastAsianLineBreaksStyle {
case EastAsianLineBreaksCSS3Draft:
style = html.EastAsianLineBreaksCSS3Draft
}
m.Renderer().AddOptions(html.WithEastAsianLineBreaks(style))
}
}
if e.EscapedSpace { if e.EscapedSpace {
m.Renderer().AddOptions(html.WithWriter(html.NewWriter(html.WithEscapedSpace()))) m.Renderer().AddOptions(html.WithWriter(html.NewWriter(html.WithEscapedSpace())))
m.Parser().AddOptions(parser.WithEscapedSpace()) m.Parser().AddOptions(parser.WithEscapedSpace())

View file

@ -17,7 +17,7 @@ import (
type Config struct { type Config struct {
Writer Writer Writer Writer
HardWraps bool HardWraps bool
EastAsianLineBreaks eastAsianLineBreaks EastAsianLineBreaks EastAsianLineBreaks
XHTML bool XHTML bool
Unsafe bool Unsafe bool
} }
@ -27,7 +27,7 @@ func NewConfig() Config {
return Config{ return Config{
Writer: DefaultWriter, Writer: DefaultWriter,
HardWraps: false, HardWraps: false,
EastAsianLineBreaks: eastAsianLineBreaks{}, EastAsianLineBreaks: EastAsianLineBreaksNone,
XHTML: false, XHTML: false,
Unsafe: false, Unsafe: false,
} }
@ -39,7 +39,7 @@ func (c *Config) SetOption(name renderer.OptionName, value interface{}) {
case optHardWraps: case optHardWraps:
c.HardWraps = value.(bool) c.HardWraps = value.(bool)
case optEastAsianLineBreaks: case optEastAsianLineBreaks:
c.EastAsianLineBreaks = value.(eastAsianLineBreaks) c.EastAsianLineBreaks = value.(EastAsianLineBreaks)
case optXHTML: case optXHTML:
c.XHTML = value.(bool) c.XHTML = value.(bool)
case optUnsafe: case optUnsafe:
@ -104,29 +104,31 @@ func WithHardWraps() interface {
// EastAsianLineBreaks is an option name used in WithEastAsianLineBreaks. // EastAsianLineBreaks is an option name used in WithEastAsianLineBreaks.
const optEastAsianLineBreaks renderer.OptionName = "EastAsianLineBreaks" const optEastAsianLineBreaks renderer.OptionName = "EastAsianLineBreaks"
// A EastAsianLineBreaksStyle is a style of east asian line breaks. // A EastAsianLineBreaks is a style of east asian line breaks.
type EastAsianLineBreaksStyle int type EastAsianLineBreaks int
const ( const (
// EastAsianLineBreaksStyleSimple follows east_asian_line_breaks in Pandoc. //EastAsianLineBreaksNone renders line breaks as it is.
EastAsianLineBreaksStyleSimple EastAsianLineBreaksStyle = iota 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 follows CSS text level3 "Segment Break Transformation Rules" with some enhancements.
EastAsianLineBreaksCSS3Draft EastAsianLineBreaksCSS3Draft
) )
type eastAsianLineBreaker interface { func (b EastAsianLineBreaks) softLineBreak(thisLastRune rune, siblingFirstRune rune) bool {
SoftLineBreak(thisLastRune rune, siblingFirstRune rune) bool switch b {
} case EastAsianLineBreaksNone:
return false
type eastAsianLineBreaksSimple struct{} case EastAsianLineBreaksSimple:
func (e *eastAsianLineBreaksSimple) SoftLineBreak(thisLastRune rune, siblingFirstRune rune) bool {
return !(util.IsEastAsianWideRune(thisLastRune) && util.IsEastAsianWideRune(siblingFirstRune)) return !(util.IsEastAsianWideRune(thisLastRune) && util.IsEastAsianWideRune(siblingFirstRune))
case EastAsianLineBreaksCSS3Draft:
return eastAsianLineBreaksCSS3DraftSoftLineBreak(thisLastRune, siblingFirstRune)
}
return false
} }
type eastAsianLineBreaksCSS3Draft struct{} func eastAsianLineBreaksCSS3DraftSoftLineBreak(thisLastRune rune, siblingFirstRune rune) bool {
func (e *eastAsianLineBreaksCSS3Draft) SoftLineBreak(thisLastRune rune, siblingFirstRune rune) bool {
// Implements CSS text level3 Segment Break Transformation Rules with some enhancements. // Implements CSS text level3 Segment Break Transformation Rules with some enhancements.
// References: // References:
// - https://www.w3.org/TR/2020/WD-css-text-3-20200429/#line-break-transform // - https://www.w3.org/TR/2020/WD-css-text-3-20200429/#line-break-transform
@ -171,52 +173,25 @@ func (e *eastAsianLineBreaksCSS3Draft) SoftLineBreak(thisLastRune rune, siblingF
return true return true
} }
type eastAsianLineBreaks struct {
Enabled bool
EastAsianLineBreaksFunction eastAsianLineBreaker
}
type withEastAsianLineBreaks struct { type withEastAsianLineBreaks struct {
eastAsianLineBreaksStyle EastAsianLineBreaksStyle eastAsianLineBreaksStyle EastAsianLineBreaks
} }
func (o *withEastAsianLineBreaks) SetConfig(c *renderer.Config) { func (o *withEastAsianLineBreaks) SetConfig(c *renderer.Config) {
switch o.eastAsianLineBreaksStyle { c.Options[optEastAsianLineBreaks] = 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) { func (o *withEastAsianLineBreaks) SetHTMLOption(c *Config) {
switch o.eastAsianLineBreaksStyle { c.EastAsianLineBreaks = 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 // WithEastAsianLineBreaks is a functional option that indicates whether softline breaks
// between east asian wide characters should be ignored. // between east asian wide characters should be ignored.
func WithEastAsianLineBreaks(style EastAsianLineBreaksStyle) interface { func WithEastAsianLineBreaks(e EastAsianLineBreaks) interface {
renderer.Option renderer.Option
Option Option
} { } {
return &withEastAsianLineBreaks{style} return &withEastAsianLineBreaks{e}
} }
// XHTML is an option name used in WithXHTML. // XHTML is an option name used in WithXHTML.
@ -759,13 +734,13 @@ func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, en
_, _ = w.WriteString("<br>\n") _, _ = w.WriteString("<br>\n")
} }
} else if n.SoftLineBreak() { } else if n.SoftLineBreak() {
if r.EastAsianLineBreaks.Enabled && len(value) != 0 { if r.EastAsianLineBreaks != EastAsianLineBreaksNone && len(value) != 0 {
sibling := node.NextSibling() sibling := node.NextSibling()
if sibling != nil && sibling.Kind() == ast.KindText { if sibling != nil && sibling.Kind() == ast.KindText {
if siblingText := sibling.(*ast.Text).Text(source); len(siblingText) != 0 { if siblingText := sibling.(*ast.Text).Text(source); len(siblingText) != 0 {
thisLastRune := util.ToRune(value, len(value)-1) thisLastRune := util.ToRune(value, len(value)-1)
siblingFirstRune, _ := utf8.DecodeRune(siblingText) siblingFirstRune, _ := utf8.DecodeRune(siblingText)
if r.EastAsianLineBreaks.EastAsianLineBreaksFunction.SoftLineBreak(thisLastRune, siblingFirstRune) { if r.EastAsianLineBreaks.softLineBreak(thisLastRune, siblingFirstRune) {
_ = w.WriteByte('\n') _ = w.WriteByte('\n')
} }
} }