Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change the range to csiParamStart/csiParamEnd #658

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion oviewer/content_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func Test_StrToContentsStyle2(t *testing.T) {
}
}

func Test_parseStringUnStyle(t *testing.T) {
func Test_StrToContentUnStyle(t *testing.T) {
t.Parallel()
type args struct {
line string
Expand Down
111 changes: 68 additions & 43 deletions oviewer/convert_es.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ const (
oscURL
)

// FinalByte is a character outside the escape sequence.
// If FinalByte is included, the interpretation of the escape sequence is terminated
// and it is considered an error as it did not terminate correctly.
const FinalByte = 0x40
// csiParamStart and csiParamEnd define the range of parameters in the CSI.
// Parameters outside this range will result in an error and will not be considered as CSI.
// Errors within this range will not affect the CSI.
const (
csiParamStart = 0x20
csiParamEnd = 0x3F
)

const (
// Colors256 is the index of the 256 color. 8-bit colors. 0-255.
Expand Down Expand Up @@ -71,6 +74,19 @@ type sgrParams struct {
// convert parses an escape sequence and changes state.
// Returns true if it is an escape sequence and a non-printing character.
func (es *escapeSequence) convert(st *parseState) bool {
switch st.mainc {
case 0x1b:
es.state = ansiEscape
return true
case '\n':
return false
}
return es.paraseEscapeSequence(st)
}

// parseEscapeSequence parses the escape sequence.
// convert parses an escape sequence and changes state.
func (es *escapeSequence) paraseEscapeSequence(st *parseState) bool {
mainc := st.mainc
switch es.state {
case ansiEscape:
Expand Down Expand Up @@ -101,24 +117,7 @@ func (es *escapeSequence) convert(st *parseState) bool {
}
return true
case ansiControlSequence:
switch {
case mainc == 'm': // SGR(Set Graphics Rendition).
st.style = sgrStyle(st.style, es.parameter.String())
case mainc == 'K':
// CSI 0 K or CSI K maintains the style after the newline
// (can change the background color of the line).
params := es.parameter.String()
if params == "" || params == "0" {
st.eolStyle = st.style
}
case mainc >= 'A' && mainc <= 'T':
// Ignore.
case mainc < FinalByte:
es.parameter.WriteRune(mainc)
return true
}
// End of escape sequence.
es.state = ansiText
es.parseCSI(st, mainc)
return true
case otherSequence:
es.state = ansiEscape
Expand Down Expand Up @@ -177,16 +176,32 @@ func (es *escapeSequence) convert(st *parseState) bool {
es.url.WriteRune(mainc)
return true
}
switch mainc {
case 0x1b:
es.state = ansiEscape
return true
case '\n':
return false
}
return false
}

// parseCSI parses the CSI(Control Sequence Introducer) escape sequence.
func (es *escapeSequence) parseCSI(st *parseState, mainc rune) {
switch {
case mainc == 'm': // SGR(Set Graphics Rendition).
st.style = sgrStyle(st.style, es.parameter.String())
case mainc == 'K': // Erase in Line.
// CSI 0 K or CSI K maintains the style after the newline
params := es.parameter.String()
if params == "" || params == "0" {
// can change the background color of the line.
_, bg, _ := st.style.Decompose()
st.eolStyle = st.eolStyle.Background(bg)
}
case mainc >= 'A' && mainc <= 'T': // Cursor Movement.
// Ignore.
case mainc >= csiParamStart && mainc <= csiParamEnd: // Parameters.
es.parameter.WriteRune(mainc)
return
}
// End of escape sequence.
es.state = ansiText
}

// sgrStyle returns tcell.Style from the SGR control sequence.
func sgrStyle(style tcell.Style, paramStr string) tcell.Style {
switch paramStr {
Expand Down Expand Up @@ -227,21 +242,12 @@ func parseSGR(paramStr string) OVStyle {
s.Italic = true
s.UnItalic = false
case 4: // Underline On
s.UnUnderline = false
s.Underline = true
if len(sgr.params) == 0 {
continue
}
// The parameter is specified(4:).
n, err := sgrNumber(sgr.params[0])
if err != nil {
return OVStyle{}
}
// Support only Underline Off (4:0).
if n == 0 {
s.Underline = false
s.UnUnderline = true
if len(sgr.params) > 0 && sgr.params[0] != "" {
s = underLineStyle(s, sgr.params[0])
break
}
s.Underline = true
s.UnUnderline = false
case 5: // Blink On
s.Blink = true
s.UnBlink = false
Expand Down Expand Up @@ -380,6 +386,25 @@ func containsNonDigit(str string) bool {
return false
}

// underLineStyle sets the underline style.
func underLineStyle(s OVStyle, param string) OVStyle {
n, err := sgrNumber(param)
if err != nil {
return s
}

// Support only Underline Off (4:0).
if n == 0 {
s.Underline = false
s.UnUnderline = true
return s
}
// Other than that, it is treated as Underline On.
s.Underline = true
s.UnUnderline = false
return s
}

// parseSGRColor parses 256 color or RGB color.
// Returns the color name and increase in the index (the colon does not increase).
func parseSGRColor(sgr sgrParams) (string, int, error) {
Expand Down
47 changes: 46 additions & 1 deletion oviewer/convert_es_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,32 @@ func Test_escapeSequence_convert(t *testing.T) {
want: true,
wantState: ansiText,
},
{
name: "test-ControlSequenceEnd",
fields: fields{
state: ansiControlSequence,
},
args: args{
st: &parseState{
mainc: '?',
},
},
want: true,
wantState: ansiControlSequence,
},
{
name: "test-ControlSequenceOver",
fields: fields{
state: ansiControlSequence,
},
args: args{
st: &parseState{
mainc: '@',
},
},
want: true,
wantState: ansiText,
},
{
name: "test-SysSequence",
fields: fields{
Expand Down Expand Up @@ -321,7 +347,7 @@ func Test_parseSGR(t *testing.T) {
{
name: "test-forground2",
args: args{
params: "38;5;2",
params: "038;05;02",
},
want: OVStyle{
Foreground: "green",
Expand All @@ -337,6 +363,25 @@ func Test_parseSGR(t *testing.T) {
},
wantErr: false,
},
{
name: "test-forground216_Underline",
args: args{
params: "38;5;216;4",
},
want: OVStyle{
Foreground: "#FFAF87",
Underline: true,
},
},
{
name: "test-reset_Underline",
args: args{
params: "38;5;216;0;4",
},
want: OVStyle{
Underline: true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
Loading