187 lines
3.9 KiB
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
|
|
}
|