1package ansi
2
3import (
4 "strconv"
5 "strings"
6)
7
8// StatusReport represents a terminal status report.
9type StatusReport interface {
10 // StatusReport returns the status report identifier.
11 StatusReport() int
12}
13
14// ANSIReport represents an ANSI terminal status report.
15type ANSIStatusReport int //nolint:revive
16
17// Report returns the status report identifier.
18func (s ANSIStatusReport) StatusReport() int {
19 return int(s)
20}
21
22// DECStatusReport represents a DEC terminal status report.
23type DECStatusReport int
24
25// Status returns the status report identifier.
26func (s DECStatusReport) StatusReport() int {
27 return int(s)
28}
29
30// DeviceStatusReport (DSR) is a control sequence that reports the terminal's
31// status.
32// The terminal responds with a DSR sequence.
33//
34// CSI Ps n
35// CSI ? Ps n
36//
37// If one of the statuses is a [DECStatus], the sequence will use the DEC
38// format.
39//
40// See also https://vt100.net/docs/vt510-rm/DSR.html
41func DeviceStatusReport(statues ...StatusReport) string {
42 var dec bool
43 list := make([]string, len(statues))
44 seq := "\x1b["
45 for i, status := range statues {
46 list[i] = strconv.Itoa(status.StatusReport())
47 switch status.(type) {
48 case DECStatusReport:
49 dec = true
50 }
51 }
52 if dec {
53 seq += "?"
54 }
55 return seq + strings.Join(list, ";") + "n"
56}
57
58// DSR is an alias for [DeviceStatusReport].
59func DSR(status StatusReport) string {
60 return DeviceStatusReport(status)
61}
62
63// RequestCursorPositionReport is an escape sequence that requests the current
64// cursor position.
65//
66// CSI 6 n
67//
68// The terminal will report the cursor position as a CSI sequence in the
69// following format:
70//
71// CSI Pl ; Pc R
72//
73// Where Pl is the line number and Pc is the column number.
74// See: https://vt100.net/docs/vt510-rm/CPR.html
75const RequestCursorPositionReport = "\x1b[6n"
76
77// RequestExtendedCursorPositionReport (DECXCPR) is a sequence for requesting
78// the cursor position report including the current page number.
79//
80// CSI ? 6 n
81//
82// The terminal will report the cursor position as a CSI sequence in the
83// following format:
84//
85// CSI ? Pl ; Pc ; Pp R
86//
87// Where Pl is the line number, Pc is the column number, and Pp is the page
88// number.
89// See: https://vt100.net/docs/vt510-rm/DECXCPR.html
90const RequestExtendedCursorPositionReport = "\x1b[?6n"
91
92// CursorPositionReport (CPR) is a control sequence that reports the cursor's
93// position.
94//
95// CSI Pl ; Pc R
96//
97// Where Pl is the line number and Pc is the column number.
98//
99// See also https://vt100.net/docs/vt510-rm/CPR.html
100func CursorPositionReport(line, column int) string {
101 if line < 1 {
102 line = 1
103 }
104 if column < 1 {
105 column = 1
106 }
107 return "\x1b[" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + "R"
108}
109
110// CPR is an alias for [CursorPositionReport].
111func CPR(line, column int) string {
112 return CursorPositionReport(line, column)
113}
114
115// ExtendedCursorPositionReport (DECXCPR) is a control sequence that reports the
116// cursor's position along with the page number (optional).
117//
118// CSI ? Pl ; Pc R
119// CSI ? Pl ; Pc ; Pv R
120//
121// Where Pl is the line number, Pc is the column number, and Pv is the page
122// number.
123//
124// If the page number is zero or negative, the returned sequence won't include
125// the page number.
126//
127// See also https://vt100.net/docs/vt510-rm/DECXCPR.html
128func ExtendedCursorPositionReport(line, column, page int) string {
129 if line < 1 {
130 line = 1
131 }
132 if column < 1 {
133 column = 1
134 }
135 if page < 1 {
136 return "\x1b[?" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + "R"
137 }
138 return "\x1b[?" + strconv.Itoa(line) + ";" + strconv.Itoa(column) + ";" + strconv.Itoa(page) + "R"
139}
140
141// DECXCPR is an alias for [ExtendedCursorPositionReport].
142func DECXCPR(line, column, page int) string {
143 return ExtendedCursorPositionReport(line, column, page)
144}