csi.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package ansi
  2. import (
  3. "bytes"
  4. "strconv"
  5. )
  6. // CsiSequence represents a control sequence introducer (CSI) sequence.
  7. //
  8. // The sequence starts with a CSI sequence, CSI (0x9B) in a 8-bit environment
  9. // or ESC [ (0x1B 0x5B) in a 7-bit environment, followed by any number of
  10. // parameters in the range of 0x30-0x3F, then by any number of intermediate
  11. // byte in the range of 0x20-0x2F, then finally with a single final byte in the
  12. // range of 0x20-0x7E.
  13. //
  14. // CSI P..P I..I F
  15. //
  16. // See ECMA-48 § 5.4.
  17. type CsiSequence struct {
  18. // Params contains the raw parameters of the sequence.
  19. // This is a slice of integers, where each integer is a 32-bit integer
  20. // containing the parameter value in the lower 31 bits and a flag in the
  21. // most significant bit indicating whether there are more sub-parameters.
  22. Params []Parameter
  23. // Cmd contains the raw command of the sequence.
  24. // The command is a 32-bit integer containing the CSI command byte in the
  25. // lower 8 bits, the private marker in the next 8 bits, and the intermediate
  26. // byte in the next 8 bits.
  27. //
  28. // CSI ? u
  29. //
  30. // Is represented as:
  31. //
  32. // 'u' | '?' << 8
  33. Cmd Command
  34. }
  35. var _ Sequence = CsiSequence{}
  36. // Clone returns a deep copy of the CSI sequence.
  37. func (s CsiSequence) Clone() Sequence {
  38. return CsiSequence{
  39. Params: append([]Parameter(nil), s.Params...),
  40. Cmd: s.Cmd,
  41. }
  42. }
  43. // Marker returns the marker byte of the CSI sequence.
  44. // This is always gonna be one of the following '<' '=' '>' '?' and in the
  45. // range of 0x3C-0x3F.
  46. // Zero is returned if the sequence does not have a marker.
  47. func (s CsiSequence) Marker() int {
  48. return s.Cmd.Marker()
  49. }
  50. // Intermediate returns the intermediate byte of the CSI sequence.
  51. // An intermediate byte is in the range of 0x20-0x2F. This includes these
  52. // characters from ' ', '!', '"', '#', '$', '%', '&', ”', '(', ')', '*', '+',
  53. // ',', '-', '.', '/'.
  54. // Zero is returned if the sequence does not have an intermediate byte.
  55. func (s CsiSequence) Intermediate() int {
  56. return s.Cmd.Intermediate()
  57. }
  58. // Command returns the command byte of the CSI sequence.
  59. func (s CsiSequence) Command() int {
  60. return s.Cmd.Command()
  61. }
  62. // Param is a helper that returns the parameter at the given index and falls
  63. // back to the default value if the parameter is missing. If the index is out
  64. // of bounds, it returns the default value and false.
  65. func (s CsiSequence) Param(i, def int) (int, bool) {
  66. if i < 0 || i >= len(s.Params) {
  67. return def, false
  68. }
  69. return s.Params[i].Param(def), true
  70. }
  71. // String returns a string representation of the sequence.
  72. // The string will always be in the 7-bit format i.e (ESC [ P..P I..I F).
  73. func (s CsiSequence) String() string {
  74. return s.buffer().String()
  75. }
  76. // buffer returns a buffer containing the sequence.
  77. func (s CsiSequence) buffer() *bytes.Buffer {
  78. var b bytes.Buffer
  79. b.WriteString("\x1b[")
  80. if m := s.Marker(); m != 0 {
  81. b.WriteByte(byte(m))
  82. }
  83. for i, p := range s.Params {
  84. param := p.Param(-1)
  85. if param >= 0 {
  86. b.WriteString(strconv.Itoa(param))
  87. }
  88. if i < len(s.Params)-1 {
  89. if p.HasMore() {
  90. b.WriteByte(':')
  91. } else {
  92. b.WriteByte(';')
  93. }
  94. }
  95. }
  96. if i := s.Intermediate(); i != 0 {
  97. b.WriteByte(byte(i))
  98. }
  99. if cmd := s.Command(); cmd != 0 {
  100. b.WriteByte(byte(cmd))
  101. }
  102. return &b
  103. }
  104. // Bytes returns the byte representation of the sequence.
  105. // The bytes will always be in the 7-bit format i.e (ESC [ P..P I..I F).
  106. func (s CsiSequence) Bytes() []byte {
  107. return s.buffer().Bytes()
  108. }