File: seq.go

package info (click to toggle)
golang-github-charmbracelet-x 0.0~git20240809.9ab0ca0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,004 kB
  • sloc: sh: 55; makefile: 5
file content (136 lines) | stat: -rw-r--r-- 3,240 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package parser

import "math"

// Shift and masks for sequence parameters and intermediates.
const (
	MarkerShift    = 8
	IntermedShift  = 16
	CommandMask    = 0xff
	HasMoreFlag    = math.MinInt32
	ParamMask      = ^HasMoreFlag
	MissingParam   = ParamMask
	MissingCommand = MissingParam
	MaxParam       = math.MaxUint16 // the maximum value a parameter can have
)

const (
	// MaxParamsSize is the maximum number of parameters a sequence can have.
	MaxParamsSize = 32

	// DefaultParamValue is the default value used for missing parameters.
	DefaultParamValue = 0
)

// Marker returns the marker byte of the 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 Marker(cmd int) int {
	return (cmd >> MarkerShift) & CommandMask
}

// Intermediate returns the intermediate byte of the 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 Intermediate(cmd int) int {
	return (cmd >> IntermedShift) & CommandMask
}

// Command returns the command byte of the CSI sequence.
func Command(cmd int) int {
	return cmd & CommandMask
}

// Param returns the parameter at the given index.
// It returns -1 if the parameter does not exist.
func Param(params []int, i int) int {
	if len(params) == 0 || i < 0 || i >= len(params) {
		return -1
	}

	p := params[i] & ParamMask
	if p == MissingParam {
		return -1
	}

	return p
}

// HasMore returns true if the parameter has more sub-parameters.
func HasMore(params []int, i int) bool {
	if len(params) == 0 || i >= len(params) {
		return false
	}

	return params[i]&HasMoreFlag != 0
}

// Subparams returns the sub-parameters of the given parameter.
// It returns nil if the parameter does not exist.
func Subparams(params []int, i int) []int {
	if len(params) == 0 || i < 0 || i >= len(params) {
		return nil
	}

	// Count the number of parameters before the given parameter index.
	var count int
	var j int
	for j = 0; j < len(params); j++ {
		if count == i {
			break
		}
		if !HasMore(params, j) {
			count++
		}
	}

	if count > i || j >= len(params) {
		return nil
	}

	var subs []int
	for ; j < len(params); j++ {
		if !HasMore(params, j) {
			break
		}
		p := Param(params, j)
		if p == -1 {
			p = DefaultParamValue
		}
		subs = append(subs, p)
	}

	p := Param(params, j)
	if p == -1 {
		p = DefaultParamValue
	}

	return append(subs, p)
}

// Len returns the number of parameters in the sequence.
// This will return the number of parameters in the sequence, excluding any
// sub-parameters.
func Len(params []int) int {
	var n int
	for i := 0; i < len(params); i++ {
		if !HasMore(params, i) {
			n++
		}
	}
	return n
}

// 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 Range(params []int, fn func(i int, param int, hasMore bool) bool) {
	for i := 0; i < len(params); i++ {
		if !fn(i, Param(params, i), HasMore(params, i)) {
			break
		}
	}
}