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