195 lines
4.2 KiB
Go

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
}