mirror of https://github.com/liamg/aminal.git
bleurgh
This commit is contained in:
parent
002d617630
commit
79be2cf8cb
|
@ -1,6 +1,8 @@
|
|||
package buffer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -24,6 +26,18 @@ func NewBuffer(viewCols uint16, viewLines uint16) *Buffer {
|
|||
return b
|
||||
}
|
||||
|
||||
func (buffer *Buffer) attachDisplayChangeHandler(handler func()) {
|
||||
|
||||
}
|
||||
|
||||
func (buffer *Buffer) attachLineChangeHandler(handler func(line uint16)) {
|
||||
|
||||
}
|
||||
|
||||
func (buffer *Buffer) attachCellChangeHandler(handler func(col uint16, line uint16)) {
|
||||
|
||||
}
|
||||
|
||||
// Column returns cursor column
|
||||
func (buffer *Buffer) CursorColumn() uint16 {
|
||||
return buffer.cursorX
|
||||
|
@ -175,6 +189,71 @@ func (buffer *Buffer) Clear() {
|
|||
buffer.SetPosition(0, 0)
|
||||
}
|
||||
|
||||
func (buffer *Buffer) getCurrentLine() (*Line, error) {
|
||||
|
||||
if int(buffer.RawLine()) < len(buffer.lines) {
|
||||
return &buffer.lines[buffer.RawLine()], nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Line %d does not exist", buffer.cursorY)
|
||||
}
|
||||
|
||||
func (buffer *Buffer) EraseLine() {
|
||||
line, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
line.cells = []Cell{}
|
||||
}
|
||||
|
||||
func (buffer *Buffer) EraseLineToCursor() {
|
||||
line, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for i := 0; i <= int(buffer.cursorX); i++ {
|
||||
if i < len(line.cells) {
|
||||
line.cells[i].erase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (buffer *Buffer) EraseLineAfterCursor() {
|
||||
line, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for i := int(buffer.cursorX + 1); i < len(line.cells); i++ {
|
||||
line.cells[i].erase()
|
||||
}
|
||||
}
|
||||
|
||||
func (buffer *Buffer) EraseDisplayAfterCursor() {
|
||||
line, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
line.cells = line.cells[:buffer.cursorX]
|
||||
for i := int(buffer.RawLine() + 1); i < buffer.Height(); i++ {
|
||||
if i < len(buffer.lines) {
|
||||
buffer.lines[i].cells = []Cell{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (buffer *Buffer) EraseDisplayToCursor() {
|
||||
line, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
line.cells = line.cells[buffer.cursorX+1:]
|
||||
for i := 0; i < int(buffer.RawLine()); i++ {
|
||||
if i < len(buffer.lines) {
|
||||
buffer.lines[i].cells = []Cell{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (buffer *Buffer) ResizeView(width uint16, height uint16) {
|
||||
buffer.viewWidth = width
|
||||
buffer.viewHeight = height
|
||||
|
|
|
@ -21,7 +21,11 @@ func newCell() Cell {
|
|||
return Cell{}
|
||||
}
|
||||
|
||||
func (cell *Cell) erase() {
|
||||
cell.setRune(0)
|
||||
}
|
||||
|
||||
func (cell *Cell) setRune(r rune) {
|
||||
cell.r = r
|
||||
cell.hasContent = true
|
||||
cell.hasContent = r > 0
|
||||
}
|
||||
|
|
|
@ -23,3 +23,27 @@ func (line *Line) String() string {
|
|||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// @todo test these (ported from legacy) ------------------
|
||||
func (line *Line) CutCellsAfter(n int) []Cell {
|
||||
cut := line.cells[n:]
|
||||
line.cells = line.cells[:n]
|
||||
return cut
|
||||
}
|
||||
|
||||
func (line *Line) CutCellsFromBeginning(n int) []Cell {
|
||||
if n > len(line.cells) {
|
||||
n = len(line.cells)
|
||||
}
|
||||
cut := line.cells[:n]
|
||||
line.cells = line.cells[n:]
|
||||
return cut
|
||||
}
|
||||
|
||||
func (line *Line) CutCellsFromEnd(n int) []Cell {
|
||||
cut := line.cells[len(line.cells)-n:]
|
||||
line.cells = line.cells[:len(line.cells)-n]
|
||||
return cut
|
||||
}
|
||||
|
||||
// -------------------------------------------------------
|
||||
|
|
|
@ -285,7 +285,7 @@ func (gui *GUI) Render() error {
|
|||
}
|
||||
|
||||
gui.font.SetColor(1, 0.2, 0.2, 0.5)
|
||||
gui.font.Printf(100, 300, 1.5, "%#v %s", gui.terminal.GetPosition(), gui.terminal.GetLineString())
|
||||
gui.font.Printf(100, 300, 1.5, "%#v", gui.terminal.GetPosition())
|
||||
|
||||
}
|
||||
|
||||
|
|
156
terminal/csi.go
156
terminal/csi.go
|
@ -8,6 +8,9 @@ import (
|
|||
|
||||
var csiSequenceMap = map[rune]csiSequenceHandler{
|
||||
'm': sgrSequenceHandler,
|
||||
'P': csiDeleteHandler,
|
||||
'J': csiEraseInDisplayHandler,
|
||||
'K': csiEraseInLineHandler,
|
||||
}
|
||||
|
||||
type csiSequenceHandler func(params []string, intermediate string, terminal *Terminal) error
|
||||
|
@ -168,101 +171,6 @@ CSI:
|
|||
terminal.position.Col = x - 1
|
||||
terminal.position.Line = y - 1
|
||||
|
||||
case 'J':
|
||||
|
||||
n := "0"
|
||||
if len(params) > 0 {
|
||||
n = params[0]
|
||||
}
|
||||
|
||||
switch n {
|
||||
|
||||
case "0", "":
|
||||
line := terminal.getBufferedLine(terminal.position.Line)
|
||||
if line != nil {
|
||||
line.Cells = line.Cells[:terminal.position.Col]
|
||||
}
|
||||
_, h := terminal.GetSize()
|
||||
for i := terminal.position.Line + 1; i < h; i++ {
|
||||
line := terminal.getBufferedLine(i)
|
||||
if line != nil {
|
||||
line.Cells = []Cell{}
|
||||
}
|
||||
}
|
||||
case "1":
|
||||
line := terminal.getBufferedLine(terminal.position.Line)
|
||||
if line != nil {
|
||||
for i := 0; i <= terminal.position.Col; i++ {
|
||||
if i < len(line.Cells) {
|
||||
line.Cells[i].r = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 0; i < terminal.position.Line; i++ {
|
||||
line := terminal.getBufferedLine(i)
|
||||
if line != nil {
|
||||
line.Cells = []Cell{}
|
||||
}
|
||||
}
|
||||
|
||||
case "2":
|
||||
_, h := terminal.GetSize()
|
||||
for i := 0; i < h; i++ {
|
||||
line := terminal.getBufferedLine(i)
|
||||
if line != nil {
|
||||
line.Cells = []Cell{}
|
||||
}
|
||||
}
|
||||
case "3":
|
||||
terminal.lines = []Line{}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Unknown CSI ED sequence: %s", n)
|
||||
}
|
||||
|
||||
case 'K': // K - EOL - Erase to end of line
|
||||
n := "0"
|
||||
if len(params) > 0 {
|
||||
n = params[0]
|
||||
}
|
||||
|
||||
switch n {
|
||||
case "0", "":
|
||||
line := terminal.getBufferedLine(terminal.position.Line)
|
||||
if line != nil {
|
||||
line.Cells = line.Cells[:terminal.position.Col]
|
||||
}
|
||||
case "1":
|
||||
line := terminal.getBufferedLine(terminal.position.Line)
|
||||
if line != nil {
|
||||
for i := 0; i <= terminal.position.Col; i++ {
|
||||
if i < len(line.Cells) {
|
||||
line.Cells[i].r = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
case "2":
|
||||
line := terminal.getBufferedLine(terminal.position.Line)
|
||||
if line != nil {
|
||||
line.Cells = []Cell{}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("Unsupported EL: %s", n)
|
||||
}
|
||||
|
||||
case 'P': // delete
|
||||
|
||||
n := 1
|
||||
if len(params) >= 1 {
|
||||
var err error
|
||||
n, err = strconv.Atoi(params[0])
|
||||
if err != nil {
|
||||
n = 1
|
||||
}
|
||||
}
|
||||
|
||||
_ = terminal.delete(n)
|
||||
|
||||
default:
|
||||
switch param + intermediate + string(final) {
|
||||
case "?25h":
|
||||
|
@ -281,3 +189,61 @@ CSI:
|
|||
//terminal.logger.Debugf("Received CSI control sequence: 0x%02X (ESC[%s%s%s)", final, param, intermediate, string(final))
|
||||
return nil
|
||||
}
|
||||
|
||||
func csiDeleteHandler(params []string, intermediate string, terminal *Terminal) error {
|
||||
n := 1
|
||||
if len(params) >= 1 {
|
||||
var err error
|
||||
n, err = strconv.Atoi(params[0])
|
||||
if err != nil {
|
||||
n = 1
|
||||
}
|
||||
}
|
||||
_ = n
|
||||
return nil
|
||||
}
|
||||
|
||||
// CSI Ps J
|
||||
func csiEraseInDisplayHandler(params []string, intermediate string, terminal *Terminal) error {
|
||||
n := "0"
|
||||
if len(params) > 0 {
|
||||
n = params[0]
|
||||
}
|
||||
|
||||
switch n {
|
||||
|
||||
case "0", "":
|
||||
terminal.buffer.EraseDisplayAfterCursor()
|
||||
case "1":
|
||||
terminal.buffer.EraseDisplayToCursor()
|
||||
case "2":
|
||||
terminal.Clear()
|
||||
case "3":
|
||||
terminal.Clear()
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Unsupported ED: CSI %s J", n)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CSI Ps K
|
||||
func csiEraseInLineHandler(params []string, intermediate string, terminal *Terminal) error {
|
||||
n := "0"
|
||||
if len(params) > 0 {
|
||||
n = params[0]
|
||||
}
|
||||
|
||||
switch n {
|
||||
case "0", "": //erase adter cursor
|
||||
terminal.buffer.EraseLineAfterCursor()
|
||||
case "1": // erase to cursor inclusive
|
||||
terminal.buffer.EraseLineToCursor()
|
||||
case "2": // erase entire
|
||||
terminal.buffer.EraseLine()
|
||||
default:
|
||||
return fmt.Errorf("Unsupported EL: CSI %s K", n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,39 +1 @@
|
|||
package terminal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (terminal *Terminal) delete(n int) error {
|
||||
if len(terminal.lines) <= terminal.position.Line {
|
||||
return fmt.Errorf("Cannot delete character at current position - line does not exist")
|
||||
}
|
||||
line := &terminal.lines[terminal.position.Line]
|
||||
|
||||
if terminal.position.Col >= len(line.Cells) {
|
||||
return fmt.Errorf("Line not long enough to delete anything")
|
||||
}
|
||||
|
||||
for terminal.position.Col+n > len(line.Cells) {
|
||||
n--
|
||||
}
|
||||
after := line.Cells[terminal.position.Col+n:]
|
||||
before := line.Cells[:terminal.position.Col]
|
||||
|
||||
line.Cells = append(before, after...)
|
||||
|
||||
// @todo rewrap lines here
|
||||
// so if line overflows and then we delete characters from beginnign of the line
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// @todo remove this debug func
|
||||
func (terminal *Terminal) GetLineString() string {
|
||||
if len(terminal.lines) <= terminal.position.Line {
|
||||
return ""
|
||||
}
|
||||
line := &terminal.lines[terminal.position.Line]
|
||||
|
||||
return line.String()
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ func (terminal *Terminal) processInput(ctx context.Context, buffer chan rune) {
|
|||
|
||||
// https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
|
||||
lineOverflow := false
|
||||
|
||||
for {
|
||||
|
||||
select {
|
||||
|
@ -41,41 +39,24 @@ func (terminal *Terminal) processInput(ctx context.Context, buffer chan rune) {
|
|||
}
|
||||
|
||||
if b != 0x0d {
|
||||
lineOverflow = false
|
||||
//lineOverflow = false
|
||||
}
|
||||
|
||||
switch b {
|
||||
case 0x0a:
|
||||
|
||||
_, h := terminal.GetSize()
|
||||
if terminal.position.Line+1 >= h {
|
||||
terminal.lines = append(terminal.lines, NewLine())
|
||||
} else {
|
||||
terminal.position.Line++
|
||||
}
|
||||
|
||||
terminal.buffer.NewLine()
|
||||
case 0x0d:
|
||||
if terminal.position.Col == 0 && terminal.position.Line > 0 && lineOverflow {
|
||||
terminal.position.Line--
|
||||
terminal.logger.Debugf("Swallowing forced new line for CR")
|
||||
lineOverflow = false
|
||||
}
|
||||
terminal.position.Col = 0
|
||||
|
||||
terminal.buffer.SetPosition(0, terminal.buffer.CursorLine())
|
||||
case 0x08:
|
||||
// backspace
|
||||
terminal.position.Col--
|
||||
if terminal.position.Col < 0 {
|
||||
terminal.position.Col = 0
|
||||
}
|
||||
terminal.buffer.MovePosition(-1, 0)
|
||||
case 0x07:
|
||||
// @todo ring bell
|
||||
default:
|
||||
// render character at current location
|
||||
// fmt.Printf("%s\n", string([]byte{b}))
|
||||
if b >= 0x20 {
|
||||
terminal.writeRune(b)
|
||||
lineOverflow = terminal.position.Col == 0
|
||||
terminal.buffer.Write(b)
|
||||
} else {
|
||||
terminal.logger.Error("Non-readable rune received: 0x%X", b)
|
||||
}
|
||||
|
|
|
@ -10,11 +10,12 @@ import (
|
|||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"gitlab.com/liamg/raft/buffer"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Terminal struct {
|
||||
lines []Line // lines, where 0 is earliest, n is latest
|
||||
buffer *buffer.Buffer
|
||||
position Position // line and col
|
||||
lock sync.Mutex
|
||||
pty *os.File
|
||||
|
@ -33,51 +34,6 @@ type Line struct {
|
|||
wrapped bool
|
||||
}
|
||||
|
||||
func NewLine() Line {
|
||||
return Line{
|
||||
Cells: []Cell{},
|
||||
}
|
||||
}
|
||||
|
||||
func (line *Line) String() string {
|
||||
s := ""
|
||||
for _, c := range line.Cells {
|
||||
s += string(c.r)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (line *Line) CutCellsAfter(n int) []Cell {
|
||||
cut := line.Cells[n:]
|
||||
line.Cells = line.Cells[:n]
|
||||
return cut
|
||||
}
|
||||
|
||||
func (line *Line) CutCellsFromBeginning(n int) []Cell {
|
||||
if n > len(line.Cells) {
|
||||
n = len(line.Cells)
|
||||
}
|
||||
cut := line.Cells[:n]
|
||||
line.Cells = line.Cells[n:]
|
||||
return cut
|
||||
}
|
||||
|
||||
func (line *Line) CutCellsFromEnd(n int) []Cell {
|
||||
cut := line.Cells[len(line.Cells)-n:]
|
||||
line.Cells = line.Cells[:len(line.Cells)-n]
|
||||
return cut
|
||||
}
|
||||
|
||||
func (line *Line) GetRenderedLength() int {
|
||||
l := 0
|
||||
for x, c := range line.Cells {
|
||||
if c.r > 0 {
|
||||
l = x
|
||||
}
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
type Winsize struct {
|
||||
Height uint16
|
||||
Width uint16
|
||||
|
@ -98,9 +54,7 @@ func New(pty *os.File, logger *zap.SugaredLogger, colourScheme ColourScheme) *Te
|
|||
}
|
||||
|
||||
return &Terminal{
|
||||
lines: []Line{
|
||||
NewLine(),
|
||||
},
|
||||
buffer: buffer.NewBuffer(0, 0),
|
||||
pty: pty,
|
||||
logger: logger,
|
||||
onUpdate: []func(){},
|
||||
|
@ -166,20 +120,6 @@ func (terminal *Terminal) Write(data []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// we have thousands of lines of output. if the terminal is X lines high, we just want to lookat the most recent X lines to render (unless scroll etc)
|
||||
func (terminal *Terminal) getBufferedLine(line int) *Line {
|
||||
|
||||
if len(terminal.lines) >= int(terminal.size.Height) {
|
||||
line = len(terminal.lines) - int(terminal.size.Height) + line
|
||||
}
|
||||
|
||||
if line < 0 || line >= len(terminal.lines) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &terminal.lines[line]
|
||||
}
|
||||
|
||||
// Read needs to be run on a goroutine, as it continually reads output to set on the terminal
|
||||
func (terminal *Terminal) Read() error {
|
||||
|
||||
|
@ -206,85 +146,8 @@ func (terminal *Terminal) Read() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (terminal *Terminal) writeRune(r rune) {
|
||||
w, h := terminal.GetSize()
|
||||
wrap := false
|
||||
if terminal.position.Col >= w {
|
||||
terminal.position.Col = 0
|
||||
terminal.position.Line++
|
||||
wrap = true
|
||||
for terminal.position.Line >= h {
|
||||
terminal.position.Line--
|
||||
line := NewLine()
|
||||
line.wrapped = true
|
||||
terminal.lines = append(terminal.lines, line)
|
||||
}
|
||||
} else {
|
||||
for terminal.position.Line >= h {
|
||||
terminal.position.Line--
|
||||
//terminal.lines = append(terminal.lines, NewLine())
|
||||
}
|
||||
}
|
||||
terminal.setRuneAtPos(terminal.position, r, wrap)
|
||||
terminal.incrementPosition()
|
||||
|
||||
}
|
||||
|
||||
func (terminal *Terminal) Clear() {
|
||||
// @todo actually should just add a bunch of newlines?
|
||||
for i := 0; i < int(terminal.size.Height); i++ {
|
||||
terminal.lines = append(terminal.lines, NewLine())
|
||||
}
|
||||
terminal.SetPosition(0, 0)
|
||||
}
|
||||
|
||||
func (terminal *Terminal) GetCellAtPos(pos Position) (*Cell, error) {
|
||||
|
||||
if int(terminal.size.Height) <= pos.Line {
|
||||
terminal.logger.Errorf("Line %d does not exist", pos.Line)
|
||||
return nil, fmt.Errorf("Line %d does not exist", pos.Line)
|
||||
}
|
||||
|
||||
if int(terminal.size.Width) <= pos.Col {
|
||||
terminal.logger.Errorf("Col %d does not exist", pos.Col)
|
||||
return nil, fmt.Errorf("Col %d does not exist", pos.Col)
|
||||
}
|
||||
|
||||
line := terminal.getBufferedLine(pos.Line)
|
||||
if line == nil {
|
||||
return nil, fmt.Errorf("Line missing")
|
||||
}
|
||||
for pos.Col >= len(line.Cells) {
|
||||
line.Cells = append(line.Cells, terminal.NewCell())
|
||||
}
|
||||
return &line.Cells[pos.Col], nil
|
||||
}
|
||||
|
||||
func (terminal *Terminal) setRuneAtPos(pos Position, r rune, wrap bool) error {
|
||||
|
||||
if int(terminal.size.Width) <= pos.Col {
|
||||
terminal.logger.Errorf("Col %d does not exist", pos.Col)
|
||||
return fmt.Errorf("Col %d does not exist", pos.Col)
|
||||
}
|
||||
|
||||
for terminal.position.Line >= len(terminal.lines) {
|
||||
nl := NewLine()
|
||||
nl.wrapped = wrap
|
||||
terminal.lines = append(terminal.lines, nl)
|
||||
}
|
||||
|
||||
line := terminal.getBufferedLine(pos.Line)
|
||||
if line == nil {
|
||||
return fmt.Errorf("Impossible?")
|
||||
}
|
||||
|
||||
for pos.Col >= len(line.Cells) {
|
||||
line.Cells = append(line.Cells, terminal.NewCell())
|
||||
}
|
||||
|
||||
line.Cells[pos.Col].attr = terminal.cellAttr
|
||||
line.Cells[pos.Col].r = r
|
||||
return nil
|
||||
terminal.buffer.Clear()
|
||||
}
|
||||
|
||||
func (terminal *Terminal) GetSize() (int, int) {
|
||||
|
@ -295,70 +158,11 @@ func (terminal *Terminal) SetSize(newCols int, newLines int) error {
|
|||
terminal.lock.Lock()
|
||||
defer terminal.lock.Unlock()
|
||||
|
||||
oldCols := int(terminal.size.Width)
|
||||
oldLines := int(terminal.size.Height)
|
||||
|
||||
if oldLines > 0 && oldCols > 0 { // only bother resizing content if there is some
|
||||
if newCols < oldCols { // if the width decreased, we need to do some line trimming
|
||||
|
||||
for l := range terminal.lines {
|
||||
if terminal.lines[l].GetRenderedLength() > newCols {
|
||||
cells := terminal.lines[l].CutCellsAfter(newCols)
|
||||
line := Line{
|
||||
Cells: cells,
|
||||
wrapped: true,
|
||||
}
|
||||
terminal.lines = append(terminal.lines[:l+1], append([]Line{line}, terminal.lines[l+1:]...)...)
|
||||
if terminal.getPosition().Line > l {
|
||||
terminal.position.Line++
|
||||
} else if terminal.getPosition().Line == l {
|
||||
if terminal.getPosition().Col >= newCols {
|
||||
//terminal.position.Line++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if newCols > oldCols { // if width increased, we need to potentially unwrap some lines
|
||||
for l := 0; l < len(terminal.lines); l++ {
|
||||
if terminal.lines[l].GetRenderedLength() < newCols { // there is space here to unwrap a line if needed
|
||||
if l+1 < len(terminal.lines) {
|
||||
if terminal.lines[l+1].wrapped {
|
||||
wrapSize := newCols - terminal.lines[l].GetRenderedLength()
|
||||
cells := terminal.lines[l+1].CutCellsFromBeginning(wrapSize)
|
||||
terminal.lines[l].Cells = append(terminal.lines[l].Cells, cells...)
|
||||
if terminal.lines[l+1].GetRenderedLength() == 0 {
|
||||
// remove line
|
||||
terminal.lines = append(terminal.lines[:l+1], terminal.lines[l+2:]...)
|
||||
if terminal.getPosition().Line >= l+1 {
|
||||
//terminal.position.Line--
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if terminal.position.Line >= newLines {
|
||||
terminal.position.Line = newLines - 1
|
||||
} else {
|
||||
linesFromEnd := oldLines - terminal.position.Line
|
||||
terminal.position.Line = newLines - linesFromEnd
|
||||
if terminal.position.Line >= len(terminal.lines) {
|
||||
terminal.position.Line = len(terminal.lines) - 1
|
||||
}
|
||||
}
|
||||
if terminal.position.Line < 0 {
|
||||
terminal.position.Line = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
terminal.size.Width = uint16(newCols)
|
||||
terminal.size.Height = uint16(newLines)
|
||||
|
||||
terminal.buffer.ResizeView(terminal.size.Width, terminal.size.Height)
|
||||
|
||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(terminal.pty.Fd()),
|
||||
uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(&terminal.size)))
|
||||
if err != 0 {
|
||||
|
|
Loading…
Reference in New Issue