| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- package ansi
- import (
- "bytes"
- "strconv"
- "github.com/charmbracelet/x/ansi/parser"
- )
- // DcsSequence represents a Device Control String (DCS) escape sequence.
- //
- // The DCS sequence is used to send device control strings to the terminal. The
- // sequence starts with the C1 control code character DCS (0x9B) or ESC P in
- // 7-bit environments, followed by parameter bytes, intermediate bytes, a
- // command byte, followed by data bytes, and ends with the C1 control code
- // character ST (0x9C) or ESC \ in 7-bit environments.
- //
- // This follows the parameter string format.
- // See ECMA-48 § 5.4.1
- type DcsSequence struct {
- // Params contains the raw parameters of the sequence.
- // This is a slice of integers, where each integer is a 32-bit integer
- // containing the parameter value in the lower 31 bits and a flag in the
- // most significant bit indicating whether there are more sub-parameters.
- Params []int
- // Data contains the string raw data of the sequence.
- // This is the data between the final byte and the escape sequence terminator.
- Data []byte
- // Cmd contains the raw command of the sequence.
- // The command is a 32-bit integer containing the DCS command byte in the
- // lower 8 bits, the private marker in the next 8 bits, and the intermediate
- // byte in the next 8 bits.
- //
- // DCS > 0 ; 1 $ r <data> ST
- //
- // Is represented as:
- //
- // 'r' | '>' << 8 | '$' << 16
- Cmd int
- }
- var _ Sequence = DcsSequence{}
- // Marker returns the marker byte of the DCS sequence.
- // This is always gonna be one of the following '<' '=' '>' '?' and in the
- // range of 0x3C-0x3F.
- // Zero is returned if the sequence does not have a marker.
- func (s DcsSequence) Marker() int {
- return parser.Marker(s.Cmd)
- }
- // Intermediate returns the intermediate byte of the DCS sequence.
- // An intermediate byte is in the range of 0x20-0x2F. This includes these
- // characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+',
- // ',', '-', '.', '/'.
- // Zero is returned if the sequence does not have an intermediate byte.
- func (s DcsSequence) Intermediate() int {
- return parser.Intermediate(s.Cmd)
- }
- // Command returns the command byte of the CSI sequence.
- func (s DcsSequence) Command() int {
- return parser.Command(s.Cmd)
- }
- // Param returns the parameter at the given index.
- // It returns -1 if the parameter does not exist.
- func (s DcsSequence) Param(i int) int {
- return parser.Param(s.Params, i)
- }
- // HasMore returns true if the parameter has more sub-parameters.
- func (s DcsSequence) HasMore(i int) bool {
- return parser.HasMore(s.Params, i)
- }
- // Subparams returns the sub-parameters of the given parameter.
- // It returns nil if the parameter does not exist.
- func (s DcsSequence) Subparams(i int) []int {
- return parser.Subparams(s.Params, i)
- }
- // Len returns the number of parameters in the sequence.
- // This will return the number of parameters in the sequence, excluding any
- // sub-parameters.
- func (s DcsSequence) Len() int {
- return parser.Len(s.Params)
- }
- // Range iterates over the parameters of the sequence and calls the given
- // function for each parameter.
- // The function should return false to stop the iteration.
- func (s DcsSequence) Range(fn func(i int, param int, hasMore bool) bool) {
- parser.Range(s.Params, fn)
- }
- // Clone returns a copy of the DCS sequence.
- func (s DcsSequence) Clone() Sequence {
- return DcsSequence{
- Params: append([]int(nil), s.Params...),
- Data: append([]byte(nil), s.Data...),
- Cmd: s.Cmd,
- }
- }
- // String returns a string representation of the sequence.
- // The string will always be in the 7-bit format i.e (ESC P p..p i..i f <data> ESC \).
- func (s DcsSequence) String() string {
- return s.buffer().String()
- }
- // buffer returns a buffer containing the sequence.
- func (s DcsSequence) buffer() *bytes.Buffer {
- var b bytes.Buffer
- b.WriteString("\x1bP")
- if m := s.Marker(); m != 0 {
- b.WriteByte(byte(m))
- }
- s.Range(func(i, param int, hasMore bool) bool {
- if param >= -1 {
- b.WriteString(strconv.Itoa(param))
- }
- if i < len(s.Params)-1 {
- if hasMore {
- b.WriteByte(':')
- } else {
- b.WriteByte(';')
- }
- }
- return true
- })
- if i := s.Intermediate(); i != 0 {
- b.WriteByte(byte(i))
- }
- b.WriteByte(byte(s.Command()))
- b.Write(s.Data)
- b.WriteByte(ESC)
- b.WriteByte('\\')
- return &b
- }
- // Bytes returns the byte representation of the sequence.
- // The bytes will always be in the 7-bit format i.e (ESC P p..p i..i F <data> ESC \).
- func (s DcsSequence) Bytes() []byte {
- return s.buffer().Bytes()
- }
|