package control import ( "io" ct "git.sdf.org/CRThaze/vtTools/encoding/codetable" mnemonic "git.sdf.org/CRThaze/vtTools/encoding/decMSCMnemonics" ) type ControlSequence struct { seq []byte } func NewControlSequence(bs ...byte) ControlSequence { cs := ControlSequence{ seq: make([]byte, len(bs), len(bs)), } copy(cs.seq, bs) return cs } func (seq ControlSequence) Bytes() []byte { return seq.seq } // func (seq ControlSequence) String() string { // return string(seq.Bytes()[:]) // } func (seq ControlSequence) Invoke(w io.Writer) { w.Write(seq.Bytes()) } type ControlSequencePrefix struct { pfx ControlSequence } func NewControlSequencePrefix(bs ...byte) ControlSequencePrefix { return ControlSequencePrefix{ pfx: NewControlSequence(bs...), } } func (pfx ControlSequencePrefix) Append(bs ...byte) ControlSequencePrefix { newLen := len(pfx.pfx.seq) + len(bs) ba := make([]byte, newLen, newLen) copy(ba, pfx.pfx.seq) ba = append(ba, bs...) return ControlSequencePrefix{ControlSequence{seq: ba}} } func (pfx ControlSequencePrefix) With(bs ...byte) ControlSequence { newLen := len(pfx.pfx.seq) + len(bs) ba := make([]byte, newLen, newLen) copy(ba, pfx.pfx.seq) ba = append(ba, bs...) return ControlSequence{seq: ba} } type SGRAttr struct { ps byte not bool } func SGR(attrs ...SGRAttr) ControlSequence { // https://web.archive.org/web/20230928233241/https://vt100.net/docs/vt220-rm/chapter4.html#S4.9 // // Set the capacity to 2 (initialization + termination) + 3 * total attrs. // Attr Ps can be up to two bytes (if negated) and when multiple are present they need one // extra byte for delimitation. ba := make([]byte, 0, (2 + (len(attrs) * 3))) // Append SGR sequence initialization control character. ba = append(ba, mnemonic.CSI) for i, attr := range attrs { if i > 0 { // Append Ps delimiter. ba = append(ba, ct.C03R11) } if attr.not { // Append negation byte. ba = append(ba, ct.C03R02) } // Append attr ID byte. ba = append(ba, attr.ps) } // Append SGR terminator. ba = append(ba, ct.C06R13) return NewControlSequence(ba...) } var ( // Prefixes EscapeCtrlPfx = NewControlSequencePrefix(mnemonic.ESC) DesignateCharSetR0CtrlPfx = EscapeCtrlPfx.Append(ct.C02R08) DesignateCharSetR1CtrlPfx = EscapeCtrlPfx.Append(ct.C02R09) DesignateCharSetR2CtrlPfx = EscapeCtrlPfx.Append(ct.C02R10) DesignateCharSetR3CtrlPfx = EscapeCtrlPfx.Append(ct.C02R11) // Complete Sequences Shifts = struct { LockShiftG0, LockShiftG1, LockShiftG1Right, LockShiftG2, LockShiftG2Right, LockShiftG3, LockShiftG3Right, SingleShiftG2, SingleShiftG3 ControlSequence LS0, LS1, LS1R, LS2, LS2R, LS3, LS3R, SS2, SS3 ControlSequence }{ // Lock Shifts LockShiftG0: NewControlSequence(mnemonic.SI), LockShiftG1: NewControlSequence(mnemonic.SO), LockShiftG1Right: EscapeCtrlPfx.With(ct.C07R14), LockShiftG2: EscapeCtrlPfx.With(ct.C06R14), LockShiftG2Right: EscapeCtrlPfx.With(ct.C07R13), LockShiftG3: EscapeCtrlPfx.With(ct.C06R15), LockShiftG3Right: EscapeCtrlPfx.With(ct.C07R12), // Single Shifts SingleShiftG2: NewControlSequence(mnemonic.SS2), SingleShiftG3: NewControlSequence(mnemonic.SS3), } SGRPs = struct { AllAttrsOff, Bold, Underline, Blink, Negative, NoBold, NoUnderline, NoBlink, Positive SGRAttr }{ AllAttrsOff: SGRAttr{ ps: ct.C03R00, }, Bold: SGRAttr{ ps: ct.C03R01, }, Underline: SGRAttr{ ps: ct.C03R04, }, Blink: SGRAttr{ ps: ct.C03R07, }, Negative: SGRAttr{ ps: ct.C03R07, }, NoBold: SGRAttr{ ps: ct.C03R01, not: true, }, NoUnderline: SGRAttr{ ps: ct.C03R04, not: true, }, NoBlink: SGRAttr{ ps: ct.C03R07, not: true, }, Positive: SGRAttr{ ps: ct.C03R07, not: true, }, } ) var UNKNOWN = append( append(SGR(SGRPs.Negative).Bytes(), ct.C03R15), SGR(SGRPs.Positive).Bytes()..., ) func init() { Shifts.LS0 = Shifts.LockShiftG0 Shifts.LS1 = Shifts.LockShiftG1 Shifts.LS1R = Shifts.LockShiftG1Right Shifts.LS2 = Shifts.LockShiftG2 Shifts.LS2R = Shifts.LockShiftG2Right Shifts.LS3 = Shifts.LockShiftG3 Shifts.LS3R = Shifts.LockShiftG3Right Shifts.SS2 = Shifts.SingleShiftG2 Shifts.SS3 = Shifts.SingleShiftG3 }