mirror of
https://github.com/yuin/goldmark
synced 2025-03-04 23:04:52 +00:00
Simplify EastAsianLineBreaks
This commit is contained in:
parent
a89ad04c49
commit
9c9003363f
3 changed files with 46 additions and 82 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue