Skip to content

Commit

Permalink
Refactor content handling
Browse files Browse the repository at this point in the history
Refactor content handling and improve special character processing.
Improve Wide Character processing to handle edge cases and optimize performance.
  • Loading branch information
noborus committed Dec 12, 2024
1 parent 09ed8fd commit 442841a
Showing 1 changed file with 100 additions and 78 deletions.
178 changes: 100 additions & 78 deletions oviewer/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type parseState struct {

// Converter is an interface for converting escape sequences, etc.
type Converter interface {
convert(*parseState) bool
convert(st *parseState) bool
}

var defaultConverter = newESConverter()
Expand All @@ -107,7 +107,6 @@ func parseString(conv Converter, str string, tabWidth int) contents {
}

// parseLine converts a string to lineContents and eolStyle, and returns them.
// If tabWidth is set to -1, \t is displayed instead of functioning as a tab.
func parseLine(conv Converter, str string, tabWidth int) (contents, tcell.Style) {
st := &parseState{
lc: make(contents, 0, len(str)),
Expand Down Expand Up @@ -138,89 +137,34 @@ func parseLine(conv Converter, str string, tabWidth int) (contents, tcell.Style)

// parseChar parses a single character.
func (st *parseState) parseChar(mainc rune, combc []rune) {
width := runewidth.RuneWidth(mainc)
if width == 0 {
st.zeroWidthHandle(mainc)
return
}

c := DefaultContent
switch runewidth.RuneWidth(mainc) {
case 0:
switch {
case mainc == '\t': // TAB
switch {
case st.tabWidth > 0:
tabStop := st.tabWidth - (st.tabx % st.tabWidth)
c.width = 1
c.style = st.style
c.mainc = rune('\t')
st.lc = append(st.lc, c)
st.tabx++
c.mainc = 0
for i := 0; i < tabStop-1; i++ {
st.lc = append(st.lc, c)
st.tabx++
}
case st.tabWidth < 0:
c.width = 1
c.style = st.style.Reverse(true)
c.mainc = rune('\\')
st.lc = append(st.lc, c)
c.mainc = rune('t')
st.lc = append(st.lc, c)
st.tabx += 2
default:
}
return
case mainc == '\b': // BackSpace
if len(st.lc) == 0 {
return
}
st.bsFlag = true
st.bsContent = st.lc.last()
if st.bsContent.width > 1 {
st.lc = st.lc[:len(st.lc)-2]
} else {
st.lc = st.lc[:len(st.lc)-1]
}
return
case mainc < 0x20: // control character
if mainc == '\r' { // CR
return
}
c.mainc = mainc
c.width = 0
st.lc = append(st.lc, c)
return
}
lastC := st.lc.last()
lastC.combc = append(lastC.combc, mainc)
n := len(st.lc) - lastC.width
if n >= 0 && len(st.lc) > n {
st.lc[n] = lastC
}
case 1:
c.mainc = mainc
if len(combc) > 0 {
c.combc = combc
}
c.width = 1
c.style = st.overstrike(c, st.style)
st.lc = append(st.lc, c)
st.tabx++
case 2:
c.mainc = mainc
if len(combc) > 0 {
c.combc = combc
}
c.width = 2
c.mainc = mainc
if len(combc) > 0 {
c.combc = combc
}
c.width = width
st.tabx += width

c.style = st.style
if st.bsFlag {
c.style = st.overstrike(c, st.style)
st.lc = append(st.lc, c, DefaultContent)
st.tabx += 2
}

st.lc = append(st.lc, c)
// multi-width character.
if width > 1 {
st.lc = append(st.lc, DefaultContent)
}
}

// overstrike set style for overstrike.
func (st *parseState) overstrike(m content, style tcell.Style) tcell.Style {
if !st.bsFlag {
return style
}

if st.bsContent.mainc == m.mainc {
style = OverStrikeStyle
} else if st.bsContent.mainc == '_' {
Expand All @@ -231,6 +175,84 @@ func (st *parseState) overstrike(m content, style tcell.Style) tcell.Style {
return style
}

// zeroWidthHandle handles zero-width characters.
func (st *parseState) zeroWidthHandle(mainc rune) {
switch {
case mainc == '\t': // TAB
st.tabHandle()
return
case mainc == '\b': // BackSpace
st.backspaceHandle()
return
case mainc == '\r': // CR
return
case mainc < 0x20: // control character
st.controlCharHandle(mainc)
return
}
lastC := st.lc.last()
lastC.combc = append(lastC.combc, mainc)
n := len(st.lc) - lastC.width
if n >= 0 && len(st.lc) > n {
st.lc[n] = lastC
}
}

// tabHandle handles the tab character.
// If tabWidth is set to -1, \t is displayed instead of functioning as a tab.
func (st *parseState) tabHandle() {
if st.tabWidth == 0 {
return
}

c := DefaultContent
if st.tabWidth < 0 { // display \t
c.width = 1
c.style = st.style.Reverse(true)
c.mainc = rune('\\')
st.lc = append(st.lc, c)
c.mainc = rune('t')
st.lc = append(st.lc, c)
st.tabx += 2
return
}

tabStop := st.tabWidth - (st.tabx % st.tabWidth)
c.width = 1
c.style = st.style
c.mainc = rune('\t')
st.lc = append(st.lc, c)
st.tabx++
c.mainc = 0
for i := 0; i < tabStop-1; i++ {
st.lc = append(st.lc, c)
st.tabx++
}
}

// backspaceHandle handles the backspace character.
func (st *parseState) backspaceHandle() {
if len(st.lc) == 0 {
return
}
st.bsFlag = true
st.bsContent = st.lc.last()

if st.bsContent.width == 1 {
st.lc = st.lc[:len(st.lc)-1]
return
}
st.lc = st.lc[:len(st.lc)-2]
}

// controlCharHandle handles control characters.
func (st *parseState) controlCharHandle(mainc rune) {
c := DefaultContent
c.mainc = mainc
c.width = 0
st.lc = append(st.lc, c)
}

// last returns the last character of Contents.
func (lc contents) last() content {
n := len(lc)
Expand Down

0 comments on commit 442841a

Please sign in to comment.