mirror of
https://github.com/bloeys/nterm.git
synced 2025-12-29 14:38:19 +00:00
Support multiple options in one SGR ansi cmd
This commit is contained in:
66
ansi/ansi.go
66
ansi/ansi.go
@ -114,32 +114,33 @@ var (
|
|||||||
// AnsiCSIStringBytesLen = len(AnsiCSIStringBytes)
|
// AnsiCSIStringBytesLen = len(AnsiCSIStringBytes)
|
||||||
)
|
)
|
||||||
|
|
||||||
type AnsiCodeOptions int64
|
type AnsiCodePayloadType int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AnsiCodeOptions_ColorFg AnsiCodeOptions = 1 << iota
|
AnsiCodePayloadType_Unknown AnsiCodePayloadType = iota
|
||||||
AnsiCodeOptions_ColorBg
|
AnsiCodePayloadType_ColorFg
|
||||||
AnsiCodeOptions_ColorDefault
|
AnsiCodePayloadType_ColorBg
|
||||||
|
AnsiCodePayloadType_Reset
|
||||||
|
|
||||||
AnsiCodeOptions_CursorOffset
|
AnsiCodePayloadType_CursorOffset
|
||||||
AnsiCodeOptions_CursorAbs
|
AnsiCodePayloadType_CursorAbs
|
||||||
AnsiCodeOptions_LineOffset
|
AnsiCodePayloadType_LineOffset
|
||||||
AnsiCodeOptions_LineAbs
|
AnsiCodePayloadType_LineAbs
|
||||||
AnsiCodeOptions_ScrollOffset
|
AnsiCodePayloadType_ScrollOffset
|
||||||
|
|
||||||
// This is at the bottom so the above iota starts at 0
|
|
||||||
AnsiCodeOptions_Unknown AnsiCodeOptions = 0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a AnsiCodeOptions) HasOptions(opts AnsiCodeOptions) bool {
|
func (a AnsiCodePayloadType) HasOption(opt AnsiCodePayloadType) bool {
|
||||||
return a&opts != 0
|
return a == opt
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnsiCodeInfoPayload struct {
|
||||||
|
Info gglm.Vec4
|
||||||
|
Type AnsiCodePayloadType
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnsiCodeInfo struct {
|
type AnsiCodeInfo struct {
|
||||||
Type CSIType
|
Type CSIType
|
||||||
// When type is CSIType_SGR and the code is reset info1.X=-1
|
Payload []AnsiCodeInfoPayload
|
||||||
Info1 gglm.Vec4
|
|
||||||
Options AnsiCodeOptions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NextAnsiCode(arr []byte) (index int, code []byte) {
|
func NextAnsiCode(arr []byte) (index int, code []byte) {
|
||||||
@ -232,7 +233,7 @@ func InfoFromAnsiCode(code []byte) (info AnsiCodeInfo) {
|
|||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
info.Type = CSIType_SGR
|
info.Type = CSIType_SGR
|
||||||
ParseSGRArgs(&info, args)
|
info.Payload = ParseSGRArgs(args)
|
||||||
case 'A':
|
case 'A':
|
||||||
info.Type = CSIType_CUU
|
info.Type = CSIType_CUU
|
||||||
case 'B':
|
case 'B':
|
||||||
@ -270,32 +271,37 @@ func InfoFromAnsiCode(code []byte) (info AnsiCodeInfo) {
|
|||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseSGRArgs(info *AnsiCodeInfo, args []byte) {
|
func ParseSGRArgs(args []byte) (payload []AnsiCodeInfoPayload) {
|
||||||
|
|
||||||
|
payload = make([]AnsiCodeInfoPayload, 0, 1)
|
||||||
|
|
||||||
// @TODO should we trim spaces?
|
// @TODO should we trim spaces?
|
||||||
splitArgs := bytes.Split(args, []byte{';'})
|
splitArgs := bytes.Split(args, []byte{';'})
|
||||||
for _, a := range splitArgs {
|
for _, a := range splitArgs {
|
||||||
|
|
||||||
if len(a) == 0 || a[0] == byte('0') {
|
if len(a) == 0 || a[0] == byte('0') {
|
||||||
info.Info1.SetX(-1)
|
payload = append(payload, AnsiCodeInfoPayload{
|
||||||
info.Options |= AnsiCodeOptions_ColorFg
|
Type: AnsiCodePayloadType_Reset,
|
||||||
continue
|
})
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO We can't use this setup of one info field because one ansi code can have many settings.
|
// @TODO We can't use this setup of one info field because one ansi code can have many settings.
|
||||||
// For example, it can set Fg+Bg at once. So we need info per option.
|
// For example, it can set Fg+Bg at once. So we need info per option.
|
||||||
intCode := getSgrIntCodeFromBytes(a)
|
intCode := getSgrIntCodeFromBytes(a)
|
||||||
if intCode >= 30 && intCode <= 37 || intCode >= 90 && intCode <= 97 {
|
if intCode >= 30 && intCode <= 37 || intCode >= 90 && intCode <= 97 {
|
||||||
|
payload = append(payload, AnsiCodeInfoPayload{
|
||||||
info.Info1 = ColorFromSgrCode(intCode)
|
Info: ColorFromSgrCode(intCode),
|
||||||
info.Options |= AnsiCodeOptions_ColorFg
|
Type: AnsiCodePayloadType_ColorFg,
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if intCode >= 40 && intCode <= 47 || intCode >= 100 && intCode <= 107 {
|
if intCode >= 40 && intCode <= 47 || intCode >= 100 && intCode <= 107 {
|
||||||
|
payload = append(payload, AnsiCodeInfoPayload{
|
||||||
info.Info1 = ColorFromSgrCode(intCode)
|
Info: ColorFromSgrCode(intCode),
|
||||||
info.Options |= AnsiCodeOptions_ColorBg
|
Type: AnsiCodePayloadType_ColorBg,
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,6 +309,8 @@ func ParseSGRArgs(info *AnsiCodeInfo, args []byte) {
|
|||||||
// @TODO Support 256 and RGB colors
|
// @TODO Support 256 and RGB colors
|
||||||
println("Code not supported yet: " + fmt.Sprint(intCode))
|
println("Code not supported yet: " + fmt.Sprint(intCode))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return payload
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSgrIntCodeFromBytes(bs []byte) (code int) {
|
func getSgrIntCodeFromBytes(bs []byte) (code int) {
|
||||||
@ -350,7 +358,7 @@ func ColorFromSgrCode(code int) gglm.Vec4 {
|
|||||||
case Ansi_Bg_Black:
|
case Ansi_Bg_Black:
|
||||||
fallthrough
|
fallthrough
|
||||||
case Ansi_Fg_Black:
|
case Ansi_Fg_Black:
|
||||||
return gglm.Vec4{}
|
return gglm.Vec4{Data: [4]float32{0, 0, 0, 1}}
|
||||||
|
|
||||||
case Ansi_Bg_Red:
|
case Ansi_Bg_Red:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|||||||
27
main.go
27
main.go
@ -444,22 +444,25 @@ func (nt *nterm) DrawTextAnsiCodesOnGlyphGrid(bs []byte) {
|
|||||||
before := bytesToRunes(bs[:index])
|
before := bytesToRunes(bs[:index])
|
||||||
draw(before)
|
draw(before)
|
||||||
|
|
||||||
//Apply code
|
//Apply codes
|
||||||
info := ansi.InfoFromAnsiCode(code)
|
ansiCodeInfo := ansi.InfoFromAnsiCode(code)
|
||||||
if info.Options.HasOptions(ansi.AnsiCodeOptions_ColorFg) {
|
// fmt.Printf("Info: %+v\n", ansiCodeInfo)
|
||||||
|
for i := 0; i < len(ansiCodeInfo.Payload); i++ {
|
||||||
|
|
||||||
if info.Info1.X() == -1 {
|
payload := &ansiCodeInfo.Payload[i]
|
||||||
|
|
||||||
|
if payload.Type.HasOption(ansi.AnsiCodePayloadType_Reset) {
|
||||||
currFgColor = nt.Settings.DefaultFgColor
|
currFgColor = nt.Settings.DefaultFgColor
|
||||||
} else {
|
currBgColor = nt.Settings.DefaultBgColor
|
||||||
currFgColor = info.Info1
|
break
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.Options.HasOptions(ansi.AnsiCodeOptions_ColorBg) {
|
if payload.Type.HasOption(ansi.AnsiCodePayloadType_ColorFg) {
|
||||||
if info.Info1.X() == -1 {
|
currFgColor = payload.Info
|
||||||
currBgColor = nt.Settings.DefaultBgColor
|
println("settings fg color to", payload.Info.String())
|
||||||
} else {
|
} else if payload.Type.HasOption(ansi.AnsiCodePayloadType_ColorBg) {
|
||||||
currBgColor = info.Info1
|
currBgColor = payload.Info
|
||||||
|
println("settings bg color to", payload.Info.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user