turbo-editors/turbo-corepublic Fork 0
v1.0.1
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

screen_write.go · 155 lines · 4.2 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 16h ago1package terminal
2
3// WriteRune puts one character at the cursor and moves on.
4//
5// The cursor stops in the last column rather than moving past it: only the
6// next character written wraps to the following line. That is what stops a
7// character in the bottom-right corner from scrolling the screen by itself,
8// which is the difference between a terminal that redraws correctly and one
9// that creeps upwards.
10func (s *Screen) WriteRune(r rune) {
11 if s.wrapPending && s.autoWrap {
12 s.CarriageReturn()
13 s.LineFeed()
14 }
15 s.wrapPending = false
16
17 s.lines[s.cursor.Row][s.cursor.Col] = Cell{Rune: r, Style: s.style}
18
19 if s.cursor.Col == s.width-1 {
20 s.wrapPending = true
21 return
22 }
23 s.cursor.Col++
24}
25
26// MoveTo puts the cursor at a position, clamped to the screen.
27func (s *Screen) MoveTo(row, col int) {
28 s.cursor.Row = min(max(row, 0), s.height-1)
29 s.cursor.Col = min(max(col, 0), s.width-1)
30 s.wrapPending = false
31}
32
33// MoveBy moves the cursor relative to where it is, clamped to the screen.
34func (s *Screen) MoveBy(rows, cols int) {
35 s.MoveTo(s.cursor.Row+rows, s.cursor.Col+cols)
36}
37
38// CarriageReturn takes the cursor to the first column of its line.
39func (s *Screen) CarriageReturn() {
40 s.cursor.Col = 0
41 s.wrapPending = false
42}
43
44// LineFeed moves the cursor down a line, scrolling the region when it is
45// already on the last row of it.
46func (s *Screen) LineFeed() {
47 s.wrapPending = false
48
49 if s.cursor.Row == s.bottom {
50 s.ScrollUp(1)
51 return
52 }
53 if s.cursor.Row < s.height-1 {
54 s.cursor.Row++
55 }
56}
57
58// ReverseLineFeed moves the cursor up a line, scrolling the region down when
59// it is already on the first row of it.
60func (s *Screen) ReverseLineFeed() {
61 s.wrapPending = false
62
63 if s.cursor.Row == s.top {
64 s.ScrollDown(1)
65 return
66 }
67 if s.cursor.Row > 0 {
68 s.cursor.Row--
69 }
70}
71
72// Backspace moves the cursor one column left, stopping at the first column.
73// It does not erase: a program that wants the character gone writes a space.
74func (s *Screen) Backspace() {
75 s.wrapPending = false
76 if s.cursor.Col > 0 {
77 s.cursor.Col--
78 }
79}
80
81// TabWidth is how far apart the default tab stops are.
82const TabWidth = 8
83
84// Tab moves the cursor to the next tab stop, or to the last column when there
85// is no further stop on the line.
86func (s *Screen) Tab() {
87 s.wrapPending = false
88 next := (s.cursor.Col/TabWidth + 1) * TabWidth
89 s.cursor.Col = min(next, s.width-1)
90}
91
92// SaveCursor remembers the cursor and the current style, as DECSC does.
93func (s *Screen) SaveCursor() {
94 s.savedCursor, s.savedStyle = s.cursor, s.style
95}
96
97// RestoreCursor puts back what SaveCursor remembered, as DECRC does.
98func (s *Screen) RestoreCursor() {
99 s.cursor, s.style = s.savedCursor, s.savedStyle
100 s.cursor.Row = min(s.cursor.Row, s.height-1)
101 s.cursor.Col = min(s.cursor.Col, s.width-1)
102 s.wrapPending = false
103}
104
105// SetScrollRegion narrows the rows that scroll to the inclusive range
106// [top, bottom], and puts the cursor at the top left as DECSTBM does.
107//
108// A region that is empty or the wrong way round is ignored, which is what a
109// terminal does with a malformed request rather than corrupting its own state.
110func (s *Screen) SetScrollRegion(top, bottom int) {
111 top = min(max(top, 0), s.height-1)
112 bottom = min(max(bottom, 0), s.height-1)
113 if top >= bottom {
114 return
115 }
116
117 s.top, s.bottom = top, bottom
118 s.MoveTo(0, 0)
119}
120
121// ScrollUp moves the scrolling region up by n lines, blanking the lines that
122// appear at the bottom. Lines leaving the top of a full-height region are kept
123// in the scrollback.
124func (s *Screen) ScrollUp(n int) {
125 rows := s.bottom - s.top + 1
126 n = min(max(n, 0), rows)
127 if n == 0 {
128 return
129 }
130
131 for i := range n {
132 s.remember(s.lines[s.top+i])
133 }
134
135 copy(s.lines[s.top:s.bottom+1-n], s.lines[s.top+n:s.bottom+1])
136 for row := s.bottom + 1 - n; row <= s.bottom; row++ {
137 s.lines[row] = s.blankLine()
138 }
139}
140
141// ScrollDown moves the scrolling region down by n lines, blanking the lines
142// that appear at the top. Nothing is remembered: these lines are not history,
143// they are being pushed back down.
144func (s *Screen) ScrollDown(n int) {
145 rows := s.bottom - s.top + 1
146 n = min(max(n, 0), rows)
147 if n == 0 {
148 return
149 }
150
151 copy(s.lines[s.top+n:s.bottom+1], s.lines[s.top:s.bottom+1-n])
152 for row := s.top; row < s.top+n; row++ {
153 s.lines[row] = s.blankLine()
154 }
155}