You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
3.1 KiB
138 lines
3.1 KiB
package terminal |
|
|
|
import ( |
|
"bytes" |
|
"syscall" |
|
"unsafe" |
|
) |
|
|
|
var COORDINATE_SYSTEM_BEGIN Short = 0 |
|
|
|
// shared variable to save the cursor location from CursorSave() |
|
var cursorLoc Coord |
|
|
|
type Cursor struct { |
|
In FileReader |
|
Out FileWriter |
|
} |
|
|
|
func (c *Cursor) Up(n int) { |
|
c.cursorMove(0, n) |
|
} |
|
|
|
func (c *Cursor) Down(n int) { |
|
c.cursorMove(0, -1*n) |
|
} |
|
|
|
func (c *Cursor) Forward(n int) { |
|
c.cursorMove(n, 0) |
|
} |
|
|
|
func (c *Cursor) Back(n int) { |
|
c.cursorMove(-1*n, 0) |
|
} |
|
|
|
// save the cursor location |
|
func (c *Cursor) Save() { |
|
cursorLoc, _ = c.Location(nil) |
|
} |
|
|
|
func (c *Cursor) Restore() { |
|
handle := syscall.Handle(c.Out.Fd()) |
|
// restore it to the original position |
|
procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursorLoc)))) |
|
} |
|
|
|
func (cur Coord) CursorIsAtLineEnd(size *Coord) bool { |
|
return cur.X == size.X |
|
} |
|
|
|
func (cur Coord) CursorIsAtLineBegin() bool { |
|
return cur.X == 0 |
|
} |
|
|
|
func (c *Cursor) cursorMove(x int, y int) { |
|
handle := syscall.Handle(c.Out.Fd()) |
|
|
|
var csbi consoleScreenBufferInfo |
|
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) |
|
|
|
var cursor Coord |
|
cursor.X = csbi.cursorPosition.X + Short(x) |
|
cursor.Y = csbi.cursorPosition.Y + Short(y) |
|
|
|
procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) |
|
} |
|
|
|
func (c *Cursor) NextLine(n int) { |
|
c.Up(n) |
|
c.HorizontalAbsolute(0) |
|
} |
|
|
|
func (c *Cursor) PreviousLine(n int) { |
|
c.Down(n) |
|
c.HorizontalAbsolute(0) |
|
} |
|
|
|
// for comparability purposes between windows |
|
// in windows we don't have to print out a new line |
|
func (c *Cursor) MoveNextLine(cur Coord, terminalSize *Coord) { |
|
c.NextLine(1) |
|
} |
|
|
|
func (c *Cursor) HorizontalAbsolute(x int) { |
|
handle := syscall.Handle(c.Out.Fd()) |
|
|
|
var csbi consoleScreenBufferInfo |
|
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) |
|
|
|
var cursor Coord |
|
cursor.X = Short(x) |
|
cursor.Y = csbi.cursorPosition.Y |
|
|
|
if csbi.size.X < cursor.X { |
|
cursor.X = csbi.size.X |
|
} |
|
|
|
procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) |
|
} |
|
|
|
func (c *Cursor) Show() { |
|
handle := syscall.Handle(c.Out.Fd()) |
|
|
|
var cci consoleCursorInfo |
|
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) |
|
cci.visible = 1 |
|
|
|
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) |
|
} |
|
|
|
func (c *Cursor) Hide() { |
|
handle := syscall.Handle(c.Out.Fd()) |
|
|
|
var cci consoleCursorInfo |
|
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) |
|
cci.visible = 0 |
|
|
|
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) |
|
} |
|
|
|
func (c *Cursor) Location(buf *bytes.Buffer) (Coord, error) { |
|
handle := syscall.Handle(c.Out.Fd()) |
|
|
|
var csbi consoleScreenBufferInfo |
|
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) |
|
|
|
return csbi.cursorPosition, nil |
|
} |
|
|
|
func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) { |
|
handle := syscall.Handle(c.Out.Fd()) |
|
|
|
var csbi consoleScreenBufferInfo |
|
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) |
|
// windows' coordinate system begins at (0, 0) |
|
csbi.size.X-- |
|
csbi.size.Y-- |
|
return &csbi.size, nil |
|
}
|
|
|