mirror of
https://github.com/yuin/goldmark
synced 2025-03-04 23:04:52 +00:00
Define EastAsianLineBreaksStyle to specify behavior of line breaking
This commit is contained in:
parent
dc2230c235
commit
9d0b1b6bb8
3 changed files with 75 additions and 60 deletions
|
|
@ -9,31 +9,31 @@ 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 EastAsianLineBreaksOption sets options for east asian line breaks.
|
// A EastAsianLineBreaksStyle is a style of east asian line breaks.
|
||||||
type EastAsianLineBreaksOption func(*eastAsianLineBreaks)
|
type EastAsianLineBreaksStyle int
|
||||||
|
|
||||||
|
const (
|
||||||
|
EastAsianLineBreaksStyleSimple EastAsianLineBreaksStyle = iota
|
||||||
|
EastAsianLineBreaksCSS3Draft
|
||||||
|
)
|
||||||
|
|
||||||
|
type EastAsianLineBreaksFunction func()
|
||||||
|
|
||||||
// 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(opts ...EastAsianLineBreaksOption) CJKOption {
|
func WithEastAsianLineBreaks(style ...EastAsianLineBreaksStyle) CJKOption {
|
||||||
return func(c *cjk) {
|
return func(c *cjk) {
|
||||||
e := &eastAsianLineBreaks{
|
e := &eastAsianLineBreaks{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
|
EastAsianLineBreaksStyle: EastAsianLineBreaksStyleSimple,
|
||||||
}
|
}
|
||||||
for _, opt := range opts {
|
for _, s := range style {
|
||||||
opt(e)
|
e.EastAsianLineBreaksStyle = s
|
||||||
}
|
}
|
||||||
c.EastAsianLineBreaks = e
|
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.
|
// WithEscapedSpace is a functional option that indicates that a '\' escaped half-space(0x20) should not be rendered.
|
||||||
func WithEscapedSpace() CJKOption {
|
func WithEscapedSpace() CJKOption {
|
||||||
return func(c *cjk) {
|
return func(c *cjk) {
|
||||||
|
|
@ -48,7 +48,7 @@ type cjk struct {
|
||||||
|
|
||||||
type eastAsianLineBreaks struct {
|
type eastAsianLineBreaks struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
WorksEvenWithOneSide 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.
|
||||||
|
|
@ -66,13 +66,13 @@ func NewCJK(opts ...CJKOption) goldmark.Extender {
|
||||||
func (e *cjk) Extend(m goldmark.Markdown) {
|
func (e *cjk) Extend(m goldmark.Markdown) {
|
||||||
if e.EastAsianLineBreaks != nil {
|
if e.EastAsianLineBreaks != nil {
|
||||||
if e.EastAsianLineBreaks.Enabled {
|
if e.EastAsianLineBreaks.Enabled {
|
||||||
opts := []html.EastAsianLineBreaksOption{}
|
style := html.EastAsianLineBreaksStyleSimple
|
||||||
if e.EastAsianLineBreaks.WorksEvenWithOneSide {
|
switch e.EastAsianLineBreaks.EastAsianLineBreaksStyle {
|
||||||
opts = append(opts, html.WithWorksEvenWithOneSide())
|
case EastAsianLineBreaksCSS3Draft:
|
||||||
|
style = html.EastAsianLineBreaksCSS3Draft
|
||||||
}
|
}
|
||||||
m.Renderer().AddOptions(html.WithEastAsianLineBreaks(opts...))
|
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())))
|
||||||
|
|
|
||||||
|
|
@ -209,13 +209,13 @@ func TestEastAsianLineBreaks(t *testing.T) {
|
||||||
t,
|
t,
|
||||||
)
|
)
|
||||||
|
|
||||||
// WithWorksEvenWithOneSide option
|
// test with EastAsianLineBreaksCSS3Draft
|
||||||
markdown = goldmark.New(goldmark.WithRendererOptions(
|
markdown = goldmark.New(goldmark.WithRendererOptions(
|
||||||
html.WithXHTML(),
|
html.WithXHTML(),
|
||||||
html.WithUnsafe(),
|
html.WithUnsafe(),
|
||||||
),
|
),
|
||||||
goldmark.WithExtensions(
|
goldmark.WithExtensions(
|
||||||
NewCJK(WithEastAsianLineBreaks(WithWorksEvenWithOneSide())),
|
NewCJK(WithEastAsianLineBreaks(EastAsianLineBreaksCSS3Draft)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
no = 9
|
no = 9
|
||||||
|
|
|
||||||
|
|
@ -103,52 +103,75 @@ 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"
|
||||||
|
|
||||||
|
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 {
|
type eastAsianLineBreaks struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
WorksEvenWithOneSide bool
|
EastAsianLineBreaksFunction eastAsianLineBreaksFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
type withEastAsianLineBreaks struct {
|
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) {
|
func (o *withEastAsianLineBreaks) SetConfig(c *renderer.Config) {
|
||||||
|
switch o.eastAsianLineBreaksStyle {
|
||||||
|
case EastAsianLineBreaksStyleSimple:
|
||||||
c.Options[optEastAsianLineBreaks] = eastAsianLineBreaks{
|
c.Options[optEastAsianLineBreaks] = eastAsianLineBreaks{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
WorksEvenWithOneSide: o.worksEvenWithOneSide,
|
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 {
|
||||||
|
case EastAsianLineBreaksStyleSimple:
|
||||||
c.EastAsianLineBreaks = eastAsianLineBreaks{
|
c.EastAsianLineBreaks = eastAsianLineBreaks{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
WorksEvenWithOneSide: o.worksEvenWithOneSide,
|
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(opts ...EastAsianLineBreaksOption) interface {
|
func WithEastAsianLineBreaks(style EastAsianLineBreaksStyle) interface {
|
||||||
renderer.Option
|
renderer.Option
|
||||||
Option
|
Option
|
||||||
} {
|
} {
|
||||||
w := &withEastAsianLineBreaks{}
|
return &withEastAsianLineBreaks{style}
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// XHTML is an option name used in WithXHTML.
|
// XHTML is an option name used in WithXHTML.
|
||||||
|
|
@ -697,17 +720,9 @@ func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, en
|
||||||
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.WorksEvenWithOneSide {
|
if r.EastAsianLineBreaks.EastAsianLineBreaksFunction.SoftLineBreak(thisLastRune, siblingFirstRune) {
|
||||||
if !(util.IsEastAsianWideRune(thisLastRune) ||
|
|
||||||
util.IsEastAsianWideRune(siblingFirstRune)) {
|
|
||||||
_ = w.WriteByte('\n')
|
_ = w.WriteByte('\n')
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if !(util.IsEastAsianWideRune(thisLastRune) &&
|
|
||||||
util.IsEastAsianWideRune(siblingFirstRune)) {
|
|
||||||
_ = w.WriteByte('\n')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue