github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/utils/virtualterm/term.go (about) 1 package virtualterm 2 3 import ( 4 "github.com/lmorg/murex/debug" 5 ) 6 7 // Term is the display state of the virtual term 8 type Term struct { 9 cells [][]cell 10 size xy 11 curPos xy 12 sgr sgr 13 state PtyState 14 //mutex sync.Mutex 15 mutex debug.BadMutex 16 } 17 18 type cell struct { 19 char rune 20 sgr sgr 21 } 22 23 type sgr struct { 24 bitwise sgrFlag 25 fg rgb 26 bg rgb 27 } 28 29 // PtyState defines some basic emulation states for the virtual TTY 30 type PtyState struct { 31 LfIncCr bool // if false, \n acts as a \r\n 32 } 33 34 func (c *cell) differs(oldChar rune, oldSgr *sgr) bool { 35 if c.sgr.bitwise != oldSgr.bitwise { 36 return true 37 } 38 39 if c.char == 0 && oldChar != 0 { 40 return true 41 } 42 43 if c.sgr.fg.Red != oldSgr.fg.Red || 44 c.sgr.fg.Green != oldSgr.fg.Green || 45 c.sgr.fg.Blue != oldSgr.fg.Blue { 46 return true 47 } 48 49 if c.sgr.bg.Red != oldSgr.bg.Red || 50 c.sgr.bg.Green != oldSgr.bg.Green || 51 c.sgr.bg.Blue != oldSgr.bg.Blue { 52 return true 53 } 54 55 return false 56 } 57 58 func (sgr *sgr) checkFlag(flag sgrFlag) bool { 59 return sgr.bitwise&flag != 0 60 } 61 62 type xy struct { 63 X int 64 Y int 65 } 66 67 type rgb struct { 68 Red, Green, Blue byte 69 } 70 71 // NewTerminal creates a new virtual term 72 func NewTerminal(x, y int) *Term { 73 cells := make([][]cell, y, y) 74 for i := range cells { 75 cells[i] = make([]cell, x, x) 76 } 77 78 return &Term{ 79 cells: cells, 80 size: xy{x, y}, 81 state: PtyState{LfIncCr: true}, 82 } 83 } 84 85 // GetSize outputs mirror those from terminal and readline packages 86 func (term *Term) GetSize() (int, int, error) { 87 return term.size.X, term.size.Y, nil 88 } 89 90 // MakeRaw sets the virtual TTY to a raw state 91 func (term *Term) MakeRaw() PtyState { 92 old := term.state 93 term.state.LfIncCr = false 94 return old 95 } 96 97 // Restore returns the virtual TTY to a previous state 98 func (term *Term) Restore(state PtyState) { 99 term.state = state 100 } 101 102 // format 103 104 func (term *Term) sgrReset() { 105 term.sgr.bitwise = 0 106 term.sgr.fg = rgb{} 107 term.sgr.bg = rgb{} 108 } 109 110 func (term *Term) sgrEffect(flag sgrFlag) { 111 term.sgr.bitwise |= flag 112 } 113 114 func (c *cell) clear() { 115 c.char = 0 116 c.sgr = sgr{} 117 } 118 119 // moveCursor functions DON'T effect other contents in the grid 120 121 func (term *Term) moveCursorBackwards(i int) (overflow int) { 122 term.curPos.X -= i 123 if term.curPos.X < 0 { 124 overflow = term.curPos.X * -1 125 term.curPos.X = 0 126 } 127 128 return 129 } 130 131 func (term *Term) moveCursorForwards(i int) (overflow int) { 132 term.curPos.X += i 133 if term.curPos.X >= term.size.X { 134 overflow = term.curPos.X - (term.size.X - 1) 135 term.curPos.X = term.size.X - 1 136 } 137 138 return 139 } 140 141 func (term *Term) moveCursorUpwards(i int) (overflow int) { 142 term.curPos.Y -= i 143 if term.curPos.Y < 0 { 144 overflow = term.curPos.Y * -1 145 term.curPos.Y = 0 146 } 147 148 return 149 } 150 151 func (term *Term) moveCursorDownwards(i int) (overflow int) { 152 term.curPos.Y += i 153 if term.curPos.Y >= term.size.Y { 154 overflow = term.curPos.Y - (term.size.Y - 1) 155 term.curPos.Y = term.size.Y - 1 156 } 157 158 return 159 } 160 161 func (term *Term) cell() *cell { return &term.cells[term.curPos.Y][term.curPos.X] } 162 163 // moveGridPos functions DO effect other contents in the grid 164 165 func (term *Term) moveContentsUp() { 166 var i int 167 for ; i < term.size.Y-1; i++ { 168 term.cells[i] = term.cells[i+1] 169 } 170 term.cells[i] = make([]cell, term.size.X, term.size.X) 171 } 172 173 func (term *Term) wrapCursorForwards() { 174 term.curPos.X += 1 175 176 if term.curPos.X >= term.size.X { 177 overflow := term.curPos.X - (term.size.X - 1) 178 term.curPos.X = 0 179 180 if overflow > 0 && term.moveCursorDownwards(1) > 0 { 181 term.moveContentsUp() 182 term.moveCursorDownwards(1) 183 } 184 } 185 } 186 187 func (term *Term) eraseDisplayAfter() { 188 for y := term.curPos.Y; y < term.size.Y; y++ { 189 for x := term.curPos.X; x < term.size.X; x++ { 190 term.cells[y][x].clear() 191 } 192 } 193 }