130 lines
2.7 KiB
Go
130 lines
2.7 KiB
Go
package textedit
|
|
|
|
import "unicode"
|
|
|
|
const nonbreakSpace = '\u00a0'
|
|
|
|
type wrapIndentState struct {
|
|
currentWord []rune
|
|
currentLineLength int
|
|
multipleLines bool
|
|
}
|
|
|
|
func indentLength(i []rune) int {
|
|
var l int
|
|
for _, ii := range i {
|
|
if ii == '\t' {
|
|
l += 8
|
|
continue
|
|
}
|
|
|
|
l++
|
|
}
|
|
|
|
return l
|
|
}
|
|
|
|
func wrapIndentEdit(first, rest []rune, firstWidth, restWidth int) func(rune, wrapIndentState) ([]rune, wrapIndentState) {
|
|
firstIndentLength := indentLength(first)
|
|
restIndentLength := indentLength(rest)
|
|
return func(r rune, state wrapIndentState) ([]rune, wrapIndentState) {
|
|
var ret []rune
|
|
indent := first
|
|
il := firstIndentLength
|
|
width := firstWidth
|
|
if state.multipleLines {
|
|
indent = rest
|
|
il = restIndentLength
|
|
width = restWidth
|
|
}
|
|
|
|
cl := state.currentLineLength
|
|
wl := len(state.currentWord)
|
|
ws := unicode.IsSpace(r) && r != nonbreakSpace
|
|
if ws && cl > 0 && cl+wl+il+1 > width && wl > 0 {
|
|
ret = append(ret, '\n')
|
|
ret = append(ret, rest...)
|
|
ret = append(ret, state.currentWord...)
|
|
state.currentLineLength = wl
|
|
state.multipleLines = true
|
|
state.currentWord = nil
|
|
return ret, state
|
|
}
|
|
|
|
if ws && cl > 0 && cl+il+1 > width {
|
|
ret = append(ret, '\n')
|
|
state.currentLineLength = 0
|
|
state.multipleLines = true
|
|
return ret, state
|
|
}
|
|
|
|
if ws && cl > 0 && wl > 0 {
|
|
ret = append(ret, ' ')
|
|
ret = append(ret, state.currentWord...)
|
|
state.currentLineLength++
|
|
state.currentLineLength += wl
|
|
state.currentWord = nil
|
|
return ret, state
|
|
}
|
|
|
|
if ws && wl > 0 {
|
|
ret = append(ret, indent...)
|
|
ret = append(ret, state.currentWord...)
|
|
state.currentLineLength += wl
|
|
state.currentWord = nil
|
|
return ret, state
|
|
}
|
|
|
|
if ws {
|
|
return nil, state
|
|
}
|
|
|
|
state.currentWord = append(state.currentWord, r)
|
|
return nil, state
|
|
}
|
|
}
|
|
|
|
func wrapIndentRelease(first, rest []rune, firstWidth, restWidth int) func(wrapIndentState) []rune {
|
|
return func(state wrapIndentState) []rune {
|
|
if len(state.currentWord) == 0 {
|
|
return nil
|
|
}
|
|
|
|
var ret []rune
|
|
indent := first
|
|
width := firstWidth
|
|
if state.multipleLines {
|
|
indent = rest
|
|
width = restWidth
|
|
}
|
|
|
|
if state.currentLineLength > 0 &&
|
|
state.currentLineLength+len(state.currentWord)+1+len(indent) > width {
|
|
ret = append(ret, '\n')
|
|
state.currentLineLength = 0
|
|
state.multipleLines = true
|
|
}
|
|
|
|
if state.multipleLines {
|
|
indent = rest
|
|
}
|
|
|
|
if state.currentLineLength == 0 {
|
|
ret = append(ret, indent...)
|
|
}
|
|
|
|
if state.currentLineLength > 0 {
|
|
ret = append(ret, ' ')
|
|
}
|
|
|
|
return append(ret, state.currentWord...)
|
|
}
|
|
}
|
|
|
|
func wrapIndent(first, rest []rune, firstWidth, restWidth int) Editor {
|
|
return Func(
|
|
wrapIndentEdit(first, rest, firstWidth, restWidth),
|
|
wrapIndentRelease(first, rest, firstWidth, restWidth),
|
|
)
|
|
}
|