vtTools/vt220/control.go

187 lines
3.9 KiB
Go

package vt220
import (
"io"
)
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, CSI)
for i, attr := range attrs {
if i > 0 {
// Append Ps delimiter.
ba = append(ba, C03R11)
}
if attr.not {
// Append negation byte.
ba = append(ba, C03R02)
}
// Append attr ID byte.
ba = append(ba, attr.ps)
}
// Append SGR terminator.
ba = append(ba, C06R13)
return NewControlSequence(ba...)
}
var (
// Prefixes
EscapeCtrlPfx = NewControlSequencePrefix(ESC)
DesignateCharSetR0CtrlPfx = EscapeCtrlPfx.Append(C02R08)
DesignateCharSetR1CtrlPfx = EscapeCtrlPfx.Append(C02R09)
DesignateCharSetR2CtrlPfx = EscapeCtrlPfx.Append(C02R10)
DesignateCharSetR3CtrlPfx = EscapeCtrlPfx.Append(C02R11)
// Complete Sequences
ShiftCtrl = 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(SI),
LockShiftG1: NewControlSequence(SO),
LockShiftG1Right: EscapeCtrlPfx.With(C07R14),
LockShiftG2: EscapeCtrlPfx.With(C06R14),
LockShiftG2Right: EscapeCtrlPfx.With(C07R13),
LockShiftG3: EscapeCtrlPfx.With(C06R15),
LockShiftG3Right: EscapeCtrlPfx.With(C07R12),
// Single Shifts
SingleShiftG2: NewControlSequence(SS2),
SingleShiftG3: NewControlSequence(SS3),
}
SGRPs = struct {
AllAttrsOff,
Bold,
Underline,
Blink,
Negative,
NoBold,
NoUnderline,
NoBlink,
Positive SGRAttr
}{
AllAttrsOff: SGRAttr{
ps: C03R00,
},
Bold: SGRAttr{
ps: C03R01,
},
Underline: SGRAttr{
ps: C03R04,
},
Blink: SGRAttr{
ps: C03R07,
},
Negative: SGRAttr{
ps: C03R07,
},
NoBold: SGRAttr{
ps: C03R01,
not: true,
},
NoUnderline: SGRAttr{
ps: C03R04,
not: true,
},
NoBlink: SGRAttr{
ps: C03R07,
not: true,
},
Positive: SGRAttr{
ps: C03R07,
not: true,
},
}
)
func init() {
ShiftCtrl.LS0 = ShiftCtrl.LockShiftG0
ShiftCtrl.LS1 = ShiftCtrl.LockShiftG1
ShiftCtrl.LS1R = ShiftCtrl.LockShiftG1Right
ShiftCtrl.LS2 = ShiftCtrl.LockShiftG2
ShiftCtrl.LS2R = ShiftCtrl.LockShiftG2Right
ShiftCtrl.LS3 = ShiftCtrl.LockShiftG3
ShiftCtrl.LS3R = ShiftCtrl.LockShiftG3Right
ShiftCtrl.SS2 = ShiftCtrl.SingleShiftG2
ShiftCtrl.SS3 = ShiftCtrl.SingleShiftG3
}