turbo-editors/turbo-corepublic Fork 0
main
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_resize.go · 95 lines · 3.1 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 12h ago1package terminal
2
3import "github.com/gdamore/tcell/v2"
4
5// Resize changes the screen's size, keeping as much of what is on it as fits.
6//
7// Lines that no longer fit at the bottom go into the scrollback rather than
8// being dropped, which is what makes shrinking a window and growing it again
9// leave the session's history intact. Columns beyond the new width are lost;
10// no terminal reflows them, and pretending otherwise would move text the
11// program believes it has already placed.
12func (s *Screen) Resize(width, height int) {
13 width, height = max(width, 1), max(height, 1)
14 if width == s.width && height == s.height {
15 return
16 }
17
18 previous := s.lines
19 s.width, s.height = width, height
20
21 dropped := rowsToDrop(len(previous), height, s.cursor.Row)
22 for i := range dropped {
23 s.remember(fitLine(previous[i], width, s.style))
24 }
25
26 s.lines = make([]Line, height)
27 for row := range height {
28 if source := row + dropped; source < len(previous) {
29 s.lines[row] = fitLine(previous[source], width, s.style)
30 } else {
31 s.lines[row] = s.blankLine()
32 }
33 }
34
35 s.cursor.Row -= dropped
36 s.resetScrollRegion()
37 s.fitCursor()
38 s.resizePrimary(width, height)
39}
40
41// resizePrimary keeps the grid put aside for the alternate screen the same
42// size as the visible one, so that leaving the alternate screen does not
43// restore a grid of the wrong shape.
44func (s *Screen) resizePrimary(width, height int) {
45 if !s.alternate {
46 return
47 }
48
49 lines := make([]Line, height)
50 for row := range height {
51 if row < len(s.primaryLines) {
52 lines[row] = fitLine(s.primaryLines[row], width, s.primaryStyle)
53 } else {
54 lines[row] = blankLineOf(width, s.primaryStyle)
55 }
56 }
57 s.primaryLines = lines
58
59 s.primaryCursor.Row = min(s.primaryCursor.Row, height-1)
60 s.primaryCursor.Col = min(s.primaryCursor.Col, width-1)
61}
62
63// fitLine returns a copy of a line at a new width, padded or cut.
64// rowsToDrop returns how many rows must come off the top when a screen shrinks.
65//
66// Only as many as it takes to keep the cursor on screen — never more.
67//
68// Dropping every row that no longer fits is the obvious rule and is wrong for
69// the common case: a command that prints one line and exits leaves the cursor
70// near the top and the rest of the screen blank, and dropping from the top then
71// throws the output away while keeping the blank rows below it. That is how
72// `echo TADA` in a tool window came out empty, the window having been created
73// at 80×24 and resized to fit its frame a moment later.
74//
75// A screen that really is full behaves as before, because a cursor at the
76// bottom needs exactly the rows that no longer fit to be dropped.
77func rowsToDrop(previous, height, cursorRow int) int {
78 needed := cursorRow - height + 1
79 return min(max(needed, 0), max(previous-height, 0))
80}
81
82func fitLine(line Line, width int, style tcell.Style) Line {
83 out := blankLineOf(width, style)
84 copy(out, line[:min(len(line), width)])
85 return out
86}
87
88// blankLineOf returns an empty line of a given width.
89func blankLineOf(width int, style tcell.Style) Line {
90 line := make(Line, width)
91 for i := range line {
92 line[i] = blank(style)
93 }
94 return line
95}